Merge topic 'contour-tree-spatial-decomposition-refactor'

cd3fe3d47 Eliminate need for SpatialDecomposition in contour tree filters.

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2825
This commit is contained in:
Gunther Weber 2022-08-03 17:11:40 +00:00 committed by Kitware Robot
commit 9551175dd4
22 changed files with 913 additions and 538 deletions

@ -548,14 +548,8 @@ int main(int argc, char* argv[])
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(0));
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
localBlockIndices.Allocate(blocksPerRank);
localBlockOrigins.Allocate(blocksPerRank);
localBlockSizes.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
{
vtkm::Id lastDimSize =
@ -604,30 +598,29 @@ int main(int argc, char* argv[])
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
vtkm::Vec<ValueType, 2> spacing(1, 1);
ds = dsb.Create(vdims, origin, spacing);
vtkm::cont::CellSetStructured<2> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cs.SetGlobalPointIndexStart(vtkm::Id2{ 0, blockIndex * blockSize });
ds.SetCellSet(cs);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(blockIndex, 0, 0));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3((blockStart / blockSliceSize), 0, 0));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(currBlockSize, static_cast<vtkm::Id>(dims[0]), 0));
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, blockIndex, 0));
}
// 3D data
else
{
vtkm::Id3 vdims;
vdims[0] = static_cast<vtkm::Id>(dims[1]);
vdims[1] = static_cast<vtkm::Id>(dims[0]);
vdims[0] = static_cast<vtkm::Id>(dims[0]);
vdims[1] = static_cast<vtkm::Id>(dims[1]);
vdims[2] = static_cast<vtkm::Id>(currBlockSize);
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
vtkm::Vec<ValueType, 3> origin(0, 0, blockIndex * blockSize);
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
ds = dsb.Create(vdims, origin, spacing);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
localBlockSizesPortal.Set(
localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), static_cast<vtkm::Id>(dims[1]), currBlockSize));
vtkm::cont::CellSetStructured<3> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(globalSize);
cs.SetGlobalPointIndexStart(vtkm::Id3{ 0, 0, blockIndex * blockSize });
ds.SetCellSet(cs);
}
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
@ -648,8 +641,7 @@ int main(int argc, char* argv[])
computeRegularStructure);
#ifdef WITH_MPI
filter.SetSpatialDecomposition(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
filter.SetBlockIndices(blocksPerDim, localBlockIndices);
#endif
filter.SetActiveField("values");

@ -401,14 +401,8 @@ int main(int argc, char* argv[])
vtkm::Id3 globalSize;
vtkm::Id3 blocksPerDim;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
localBlockIndices.Allocate(blocksPerRank);
localBlockOrigins.Allocate(blocksPerRank);
localBlockSizes.Allocate(blocksPerRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
// Read the pre-split data files
if (preSplitFiles)
@ -595,6 +589,11 @@ int main(int argc, char* argv[])
static_cast<ValueType>(offset[1]) };
const vtkm::Vec<ValueType, 2> v_spacing{ 1, 1 };
ds = dsb.Create(v_dims, v_origin, v_spacing);
vtkm::cont::CellSetStructured<2> cs;
cs.SetPointDimensions(v_dims);
cs.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cs.SetGlobalPointIndexStart(vtkm::Id2{ offset[0], offset[1] });
ds.SetCellSet(cs);
}
else
{
@ -607,6 +606,11 @@ int main(int argc, char* argv[])
static_cast<ValueType>(offset[2]) };
vtkm::Vec<ValueType, 3> v_spacing(1, 1, 1);
ds = dsb.Create(v_dims, v_origin, v_spacing);
vtkm::cont::CellSetStructured<3> cs;
cs.SetPointDimensions(v_dims);
cs.SetGlobalPointDimensions(globalSize);
cs.SetGlobalPointIndexStart(vtkm::Id3{ offset[0], offset[1], offset[2] });
ds.SetCellSet(cs);
}
ds.AddPointField("values", values);
// and add to partition
@ -617,14 +621,6 @@ int main(int argc, char* argv[])
vtkm::Id3{ static_cast<vtkm::Id>(blockIndex[0]),
static_cast<vtkm::Id>(blockIndex[1]),
static_cast<vtkm::Id>(nDims == 3 ? blockIndex[2] : 0) });
localBlockOriginsPortal.Set(blockNo,
vtkm::Id3{ static_cast<vtkm::Id>(offset[0]),
static_cast<vtkm::Id>(offset[1]),
static_cast<vtkm::Id>(nDims == 3 ? offset[2] : 0) });
localBlockSizesPortal.Set(blockNo,
vtkm::Id3{ static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(nDims == 3 ? dims[2] : 0) });
if (blockNo == 0)
{
@ -753,7 +749,6 @@ int main(int argc, char* argv[])
: vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
static_cast<vtkm::Id>(1));
std::cout << blocksPerDim << " " << globalSize << std::endl;
{
vtkm::Id lastDimSize =
(nDims == 2) ? static_cast<vtkm::Id>(dims[1]) : static_cast<vtkm::Id>(dims[2]);
@ -801,12 +796,12 @@ int main(int argc, char* argv[])
vtkm::Vec<ValueType, 2> origin(0, blockIndex * blockSize);
vtkm::Vec<ValueType, 2> spacing(1, 1);
ds = dsb.Create(vdims, origin, spacing);
vtkm::cont::CellSetStructured<2> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cs.SetGlobalPointIndexStart(vtkm::Id2{ 0, (blockStart / blockSliceSize) });
ds.SetCellSet(cs);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, blockIndex, 0));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, (blockStart / blockSliceSize), 0));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]), currBlockSize, 0));
}
// 3D data
else
@ -818,14 +813,12 @@ int main(int argc, char* argv[])
vtkm::Vec<ValueType, 3> origin(0, 0, (blockIndex * blockSize));
vtkm::Vec<ValueType, 3> spacing(1, 1, 1);
ds = dsb.Create(vdims, origin, spacing);
vtkm::cont::CellSetStructured<3> cs;
cs.SetPointDimensions(vdims);
cs.SetGlobalPointDimensions(globalSize);
cs.SetGlobalPointIndexStart(vtkm::Id3(0, 0, blockStart / blockSliceSize));
ds.SetCellSet(cs);
localBlockIndicesPortal.Set(localBlockIndex, vtkm::Id3(0, 0, blockIndex));
localBlockOriginsPortal.Set(localBlockIndex,
vtkm::Id3(0, 0, (blockStart / blockSliceSize)));
localBlockSizesPortal.Set(localBlockIndex,
vtkm::Id3(static_cast<vtkm::Id>(dims[0]),
static_cast<vtkm::Id>(dims[1]),
currBlockSize));
}
std::vector<vtkm::Float32> subValues((values.begin() + blockStart),
@ -863,13 +856,9 @@ int main(int argc, char* argv[])
prevTime = currTime;
// Convert the mesh of values into contour tree, pairs of vertex ids
vtkm::filter::ContourTreeUniformDistributed filter(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes,
timingsLogLevel,
treeLogLevel);
vtkm::filter::scalar_topology::ContourTreeUniformDistributed filter(timingsLogLevel,
treeLogLevel);
filter.SetBlockIndices(blocksPerDim, localBlockIndices);
filter.SetUseBoundaryExtremaOnly(useBoundaryExtremaOnly);
filter.SetUseMarchingCubes(useMarchingCubes);
filter.SetAugmentHierarchicalTree(augmentHierarchicalTree);
@ -895,8 +884,7 @@ int main(int argc, char* argv[])
{
if (computeHierarchicalVolumetricBranchDecomposition)
{
vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter bd_filter(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter bd_filter;
auto bd_result = bd_filter.Execute(result);
for (vtkm::Id ds_no = 0; ds_no < result.GetNumberOfPartitions(); ++ds_no)

@ -51,6 +51,11 @@ public:
this->Structure.SetPointDimensions(dimensions);
}
void SetGlobalPointDimensions(SchedulingRangeType dimensions)
{
this->Structure.SetGlobalPointDimensions(dimensions);
}
void SetGlobalPointIndexStart(SchedulingRangeType start)
{
this->Structure.SetGlobalPointIndexStart(start);
@ -58,8 +63,18 @@ public:
SchedulingRangeType GetPointDimensions() const { return this->Structure.GetPointDimensions(); }
SchedulingRangeType GetGlobalPointDimensions() const
{
return this->Structure.GetGlobalPointDimensions();
}
SchedulingRangeType GetCellDimensions() const { return this->Structure.GetCellDimensions(); }
SchedulingRangeType GetGlobalCellDimensions() const
{
return this->Structure.GetGlobalCellDimensions();
}
SchedulingRangeType GetGlobalPointIndexStart() const
{
return this->Structure.GetGlobalPointIndexStart();
@ -225,17 +240,20 @@ public:
static VTKM_CONT void save(BinaryBuffer& bb, const Type& cs)
{
vtkmdiy::save(bb, cs.GetPointDimensions());
vtkmdiy::save(bb, cs.GetGlobalPointDimensions());
vtkmdiy::save(bb, cs.GetGlobalPointIndexStart());
}
static VTKM_CONT void load(BinaryBuffer& bb, Type& cs)
{
typename Type::SchedulingRangeType dims, start;
typename Type::SchedulingRangeType dims, gdims, start;
vtkmdiy::load(bb, dims);
vtkmdiy::load(bb, gdims);
vtkmdiy::load(bb, start);
cs = Type{};
cs.SetPointDimensions(dims);
cs.SetGlobalPointDimensions(gdims);
cs.SetGlobalPointIndexStart(start);
}
};

@ -15,6 +15,13 @@
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/Field.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/internal/Configure.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
namespace vtkm
{
@ -73,6 +80,19 @@ vtkm::Id PartitionedDataSet::GetNumberOfPartitions() const
return static_cast<vtkm::Id>(this->Partitions.size());
}
VTKM_CONT
vtkm::Id PartitionedDataSet::GetGlobalNumberOfPartitions() const
{
#ifdef VTKM_ENABLE_MPI
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
vtkm::Id globalSize = 0;
vtkmdiy::mpi::all_reduce(comm, GetNumberOfPartitions(), globalSize, std::plus<vtkm::Id>{});
return globalSize;
#else
return GetNumberOfPartitions();
#endif
}
VTKM_CONT
const vtkm::cont::DataSet& PartitionedDataSet::GetPartition(vtkm::Id blockId) const
{

@ -32,16 +32,16 @@ public:
using reference = typename StorageVec::reference;
using const_reference = typename StorageVec::const_reference;
/// create a new PartitionedDataSet containng a single DataSet @a ds
/// Create a new PartitionedDataSet containng a single DataSet @a ds.
VTKM_CONT
PartitionedDataSet(const vtkm::cont::DataSet& ds);
/// create a new PartitionedDataSet with the existing one @a src
/// Create a new PartitionedDataSet with the existing one @a src.
VTKM_CONT
PartitionedDataSet(const vtkm::cont::PartitionedDataSet& src);
/// create a new PartitionedDataSet with a DataSet vector @a partitions.
/// Create a new PartitionedDataSet with a DataSet vector @a partitions.
VTKM_CONT
explicit PartitionedDataSet(const std::vector<vtkm::cont::DataSet>& partitions);
/// create a new PartitionedDataSet with the capacity set to be @a size
/// Create a new PartitionedDataSet with the capacity set to be @a size.
VTKM_CONT
explicit PartitionedDataSet(vtkm::Id size);
@ -53,33 +53,41 @@ public:
VTKM_CONT
~PartitionedDataSet();
/// get the field @a field_name from partition @a partition_index
/// Get the field @a field_name from partition @a partition_index.
VTKM_CONT
vtkm::cont::Field GetField(const std::string& field_name, int partition_index) const;
/// Get number of DataSet objects stored in this PartitionedDataSet.
VTKM_CONT
vtkm::Id GetNumberOfPartitions() const;
/// Get number of partations across all MPI ranks.
/// @warning This method requires global communication (MPI_Allreduce) if MPI is enabled.
VTKM_CONT
vtkm::Id GetGlobalNumberOfPartitions() const;
/// Get the DataSet @a partId.
VTKM_CONT
const vtkm::cont::DataSet& GetPartition(vtkm::Id partId) const;
/// Get an STL vector of all DataSet objects stored in PartitionedDataSet.
VTKM_CONT
const std::vector<vtkm::cont::DataSet>& GetPartitions() const;
/// add DataSet @a ds to the end of the contained DataSet vector
/// Add DataSet @a ds to the end of the contained DataSet vector.
VTKM_CONT
void AppendPartition(const vtkm::cont::DataSet& ds);
/// add DataSet @a ds to position @a index of the contained DataSet vector
/// Add DataSet @a ds to position @a index of the contained DataSet vector.
VTKM_CONT
void InsertPartition(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// replace the @a index positioned element of the contained DataSet vector
/// with @a ds
/// Replace the @a index positioned element of the contained DataSet vector
/// with @a ds.
VTKM_CONT
void ReplacePartition(vtkm::Id index, const vtkm::cont::DataSet& ds);
/// append the DataSet vector "partitions" to the end of the contained one
/// Append the DataSet vector @a partitions to the end of the contained one.
VTKM_CONT
void AppendPartitions(const std::vector<vtkm::cont::DataSet>& partitions);

@ -16,6 +16,7 @@ set(scalar_topology_headers
set(scalar_topology_sources
internal/BranchDecompositionBlock.cxx
internal/ComputeBlockIndices.cxx
internal/ComputeDistributedBranchDecompositionFunctor.cxx
ContourTreeUniform.cxx
ContourTreeUniformAugmented.cxx

@ -51,6 +51,7 @@
//==============================================================================
#include <vtkm/filter/scalar_topology/ContourTreeUniformAugmented.h>
#include <vtkm/filter/scalar_topology/internal/ComputeBlockIndices.h>
#include <vtkm/filter/scalar_topology/worklet/ContourTreeUniformAugmented.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
@ -83,12 +84,9 @@ ContourTreeAugmented::ContourTreeAugmented(bool useMarchingCubes,
this->SetOutputFieldName("resultData");
}
void ContourTreeAugmented::SetSpatialDecomposition(
void ContourTreeAugmented::SetBlockIndices(
vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes)
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices)
{
if (this->MultiBlockTreeHelper)
{
@ -96,7 +94,7 @@ void ContourTreeAugmented::SetSpatialDecomposition(
}
this->MultiBlockTreeHelper =
std::make_unique<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>(
blocksPerDim, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
blocksPerDim, localBlockIndices);
}
const vtkm::worklet::contourtree_augmented::ContourTree& ContourTreeAugmented::GetContourTree()
@ -234,7 +232,7 @@ VTKM_CONT void ContourTreeAugmented::PreExecute(const vtkm::cont::PartitionedDat
{
if (this->MultiBlockTreeHelper)
{
if (this->MultiBlockTreeHelper->GetGlobalNumberOfBlocks(input) !=
if (input.GetGlobalNumberOfPartitions() !=
this->MultiBlockTreeHelper->GetGlobalNumberOfBlocks())
{
throw vtkm::cont::ErrorFilterExecution(
@ -246,6 +244,12 @@ VTKM_CONT void ContourTreeAugmented::PreExecute(const vtkm::cont::PartitionedDat
"Global number of block in MultiBlock dataset does not match the SpatialDecomposition");
}
}
else
{
// No block indices set -> compute information automatically later
this->MultiBlockTreeHelper =
std::make_unique<vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper>(input);
}
}
//-----------------------------------------------------------------------------
@ -268,10 +272,6 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
unsigned int compRegularStruct =
(this->ComputeRegularStructure > 0) ? this->ComputeRegularStructure : 2;
auto localBlocksOriginPortal =
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal();
auto localBlocksSizesPortal =
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal();
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
{
// create the local contour tree mesh
@ -279,20 +279,25 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
auto currBlock = input.GetPartition(static_cast<vtkm::Id>(bi));
auto currField =
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
vtkm::Id3 pointDimensions, globalPointDimensions, globalPointIndexStart;
currBlock.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
pointDimensions,
globalPointDimensions,
globalPointIndexStart);
//const vtkm::cont::ArrayHandle<T,StorageType> &fieldData = currField.GetData().Cast<vtkm::cont::ArrayHandle<T,StorageType> >();
vtkm::cont::ArrayHandle<T> fieldData;
vtkm::cont::ArrayCopy(currField.GetData(), fieldData);
auto currContourTreeMesh = vtkm::worklet::contourtree_distributed::MultiBlockContourTreeHelper::
ComputeLocalContourTreeMesh<T>(
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal()
.Get(static_cast<vtkm::Id>(bi)),
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
static_cast<vtkm::Id>(bi)),
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize,
fieldData,
MultiBlockTreeHelper->LocalContourTrees[bi],
MultiBlockTreeHelper->LocalSortOrders[bi],
compRegularStruct);
ComputeLocalContourTreeMesh<T>(globalPointIndexStart,
pointDimensions,
globalPointDimensions,
fieldData,
MultiBlockTreeHelper->LocalContourTrees[bi],
MultiBlockTreeHelper->LocalSortOrders[bi],
compRegularStruct);
localContourTreeMeshes[bi] = currContourTreeMesh;
// create the local data block structure
localDataBlocks[bi] = new vtkm::worklet::contourtree_distributed::ContourTreeBlockData<T>();
@ -303,10 +308,9 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
localDataBlocks[bi]->NeighborConnectivity = currContourTreeMesh->NeighborConnectivity;
localDataBlocks[bi]->NeighborOffsets = currContourTreeMesh->NeighborOffsets;
localDataBlocks[bi]->MaxNeighbors = currContourTreeMesh->MaxNeighbors;
localDataBlocks[bi]->BlockOrigin = localBlocksOriginPortal.Get(static_cast<vtkm::Id>(bi));
localDataBlocks[bi]->BlockSize = localBlocksSizesPortal.Get(static_cast<vtkm::Id>(bi));
localDataBlocks[bi]->GlobalSize =
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize;
localDataBlocks[bi]->BlockOrigin = globalPointIndexStart;
localDataBlocks[bi]->BlockSize = pointDimensions;
localDataBlocks[bi]->GlobalSize = globalPointDimensions;
// We need to augment at least with the boundary vertices when running in parallel
localDataBlocks[bi]->ComputeRegularStructure = compRegularStruct;
}
@ -320,33 +324,32 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
// Compute the gids for our local blocks
using RegularDecomposer = vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>;
const vtkm::filter::scalar_topology::internal::SpatialDecomposition& spatialDecomp =
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition;
const auto numDims = spatialDecomp.NumberOfDimensions();
// ... division vector
RegularDecomposer::DivisionsVector diyDivisions(numDims);
for (vtkm::IdComponent d = 0;
d < static_cast<vtkm::IdComponent>(spatialDecomp.NumberOfDimensions());
++d)
RegularDecomposer::DivisionsVector diyDivisions;
std::vector<int> vtkmdiyLocalBlockGids;
vtkmdiy::DiscreteBounds diyBounds(0);
if (this->MultiBlockTreeHelper->BlocksPerDimension[0] == -1)
{
diyDivisions[d] = static_cast<int>(spatialDecomp.BlocksPerDimension[d]);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"BlocksPerDimension not set. Computing block indices "
"from information in CellSetStructured.");
diyBounds = vtkm::filter::scalar_topology::internal::ComputeBlockIndices(
input, diyDivisions, vtkmdiyLocalBlockGids);
}
// ... coordinates of local blocks
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
std::vector<vtkm::Id> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
else
{
RegularDecomposer::DivisionsVector diyCoords(static_cast<size_t>(numDims));
auto currentCoords = localBlockIndicesPortal.Get(bi);
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
diyCoords[d] = static_cast<int>(currentCoords[d]);
}
vtkmdiyLocalBlockGids[static_cast<size_t>(bi)] =
RegularDecomposer::coords_to_gid(diyCoords, diyDivisions);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"BlocksPerDimension set. Using information provided by caller.");
diyBounds = vtkm::filter::scalar_topology::internal::ComputeBlockIndices(
input,
this->MultiBlockTreeHelper->BlocksPerDimension,
this->MultiBlockTreeHelper->LocalBlockIndices,
diyDivisions,
vtkmdiyLocalBlockGids);
}
int numDims = diyBounds.min.dimension();
int globalNumberOfBlocks =
std::accumulate(diyDivisions.cbegin(), diyDivisions.cend(), 1, std::multiplies<int>{});
// Add my local blocks to the vtkmdiy master.
for (std::size_t bi = 0; bi < static_cast<std::size_t>(input.GetNumberOfPartitions()); bi++)
@ -361,16 +364,15 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
RegularDecomposer::BoolVector wrap(3, false);
RegularDecomposer::CoordinateVector ghosts(3, 1);
RegularDecomposer decomposer(static_cast<int>(numDims),
spatialDecomp.GetVTKmDIYBounds(),
static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()),
diyBounds,
globalNumberOfBlocks,
shareFace,
wrap,
ghosts,
diyDivisions);
// Define which blocks live on which rank so that vtkmdiy can manage them
vtkmdiy::DynamicAssigner assigner(
comm, static_cast<int>(size), static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
vtkmdiy::DynamicAssigner assigner(comm, static_cast<int>(size), globalNumberOfBlocks);
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
assigner.set_rank(static_cast<int>(rank),
@ -394,6 +396,13 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
if (rank == 0)
{
vtkm::Id3 dummy1, globalPointDimensions, dummy2;
vtkm::cont::DataSet firstDS = input.GetPartition(0);
firstDS.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
dummy1,
globalPointDimensions,
dummy2);
// Now run the contour tree algorithm on the last block to compute the final tree
vtkm::Id currNumIterations;
vtkm::worklet::contourtree_augmented::ContourTree currContourTree;
@ -412,12 +421,12 @@ VTKM_CONT void ContourTreeAugmented::DoPostExecute(const vtkm::cont::Partitioned
contourTreeMeshOut.MaxNeighbors = localDataBlocks[0]->MaxNeighbors;
// Construct the mesh boundary exectuion object needed for boundary augmentation
vtkm::Id3 minIdx(0, 0, 0);
vtkm::Id3 maxIdx = this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize;
vtkm::Id3 maxIdx = globalPointDimensions;
maxIdx[0] = maxIdx[0] - 1;
maxIdx[1] = maxIdx[1] - 1;
maxIdx[2] = maxIdx[2] > 0 ? (maxIdx[2] - 1) : 0;
auto meshBoundaryExecObj = contourTreeMeshOut.GetMeshBoundaryExecutionObject(
this->MultiBlockTreeHelper->MultiBlockSpatialDecomposition.GlobalSize, minIdx, maxIdx);
auto meshBoundaryExecObj =
contourTreeMeshOut.GetMeshBoundaryExecutionObject(globalPointDimensions, minIdx, maxIdx);
// Run the worklet to compute the final contour tree
worklet.Run(
contourTreeMeshOut.SortedValues, // Unused param. Provide something to keep API happy

@ -114,19 +114,24 @@ public:
///
/// Note: Only used when running on a multi-block dataset.
/// @param[in] blocksPerDim Number of data blocks used in each data dimension
/// @param[in] globalSize Global extends of the input mesh (i.e., number of mesh points in each dimension)
/// @param[in] localBlockIndices Array with the (x,y,z) index of each local data block with
/// with respect to blocksPerDim
/// @param[in] localBlockOrigins Array with the (x,y,z) origin (with regard to mesh index) of each
/// local data block
/// @param[in] localBlockSizes Array with the sizes (i.e., extends in number of mesh points) of each
/// local data block
VTKM_CONT
void SetBlockIndices(vtkm::Id3 blocksPerDim,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices);
VTKM_CONT
VTKM_DEPRECATED(1.9,
"Set PointSize, GlobalPointOrigin, and GlobalPointSize in CellSetStructured and "
"optionally use SetBlockIndices.")
void SetSpatialDecomposition(vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
vtkm::Id3,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes);
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&)
{
SetBlockIndices(blocksPerDim, localBlockIndices);
}
//@{
/// Get the contour tree computed by the filter

@ -51,6 +51,7 @@
//==============================================================================
// vtkm includes
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/Timer.h>
@ -61,7 +62,7 @@
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/mesh_boundary/MeshBoundaryContourTreeMesh.h>
// distributed contour tree includes
#include <vtkm/filter/scalar_topology/internal/SpatialDecomposition.h>
#include <vtkm/filter/scalar_topology/internal/ComputeBlockIndices.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/BoundaryTree.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/BoundaryTreeMaker.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/CombineHyperSweepBlockFunctor.h>
@ -165,10 +166,10 @@ void SaveHierarchicalTreeDot(
//-----------------------------------------------------------------------------
ContourTreeUniformDistributed::ContourTreeUniformDistributed(
vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
vtkm::Id3, // globalSize, -> Now in CellSetStructured
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
const vtkm::cont::ArrayHandle<vtkm::Id3>&, // localBlockOrigins, -> Use from CellSetStructured
const vtkm::cont::ArrayHandle<vtkm::Id3>&, // localBlockSizes, -> Use from CellSetStructured
vtkm::cont::LogLevel timingsLogLevel,
vtkm::cont::LogLevel treeLogLevel)
: UseBoundaryExtremaOnly(true)
@ -177,19 +178,33 @@ ContourTreeUniformDistributed::ContourTreeUniformDistributed(
, SaveDotFiles(false)
, TimingsLogLevel(timingsLogLevel)
, TreeLogLevel(treeLogLevel)
, MultiBlockSpatialDecomposition(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes)
, LocalMeshes(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
, LocalContourTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
, LocalBoundaryTrees(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
, LocalInteriorForests(static_cast<std::size_t>(localBlockSizes.GetNumberOfValues()))
, BlocksPerDimension(blocksPerDim)
, LocalBlockIndices(localBlockIndices)
, LocalMeshes()
, LocalContourTrees()
, LocalBoundaryTrees()
, LocalInteriorForests()
{
this->SetOutputFieldName("resultData");
}
ContourTreeUniformDistributed::ContourTreeUniformDistributed(vtkm::cont::LogLevel timingsLogLevel,
vtkm::cont::LogLevel treeLogLevel)
: UseBoundaryExtremaOnly(true)
, UseMarchingCubes(false)
, AugmentHierarchicalTree(false)
, SaveDotFiles(false)
, TimingsLogLevel(timingsLogLevel)
, TreeLogLevel(treeLogLevel)
, BlocksPerDimension(vtkm::Id3{ -1, -1, -1 })
, LocalBlockIndices()
, LocalMeshes()
, LocalContourTrees()
, LocalBoundaryTrees()
, LocalInteriorForests()
{
this->SetOutputFieldName("resultData");
}
//-----------------------------------------------------------------------------
// Functions used in PrepareForExecution() to compute the local contour
@ -237,7 +252,7 @@ void ContourTreeUniformDistributed::ComputeLocalTree(
template <typename T, typename StorageType, typename MeshType, typename MeshBoundaryExecType>
void ContourTreeUniformDistributed::ComputeLocalTreeImpl(
const vtkm::Id blockIndex,
const vtkm::cont::DataSet&, // input,
const vtkm::cont::DataSet& ds, // input,
const vtkm::cont::ArrayHandle<T, StorageType>& field,
MeshType& mesh,
MeshBoundaryExecType& meshBoundaryExecObject)
@ -278,10 +293,14 @@ void ContourTreeUniformDistributed::ComputeLocalTreeImpl(
// Create an IdRelabeler since we are using a DataSetMesh type here, we don't need
// the IdRelabeler for the BRACT construction when we are using a ContourTreeMesh.
vtkm::Id3 pointDimensions, globalPointDimensions, globalPointIndexStart;
ds.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
pointDimensions,
globalPointDimensions,
globalPointIndexStart);
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
this->MultiBlockSpatialDecomposition.GlobalSize);
globalPointIndexStart, pointDimensions, globalPointDimensions);
// Initialize the BoundaryTreeMaker
auto boundaryTreeMaker =
vtkm::worklet::contourtree_distributed::BoundaryTreeMaker<MeshType, MeshBoundaryExecType>(
@ -322,9 +341,9 @@ void ContourTreeUniformDistributed::ComputeLocalTreeImpl(
"Before Fan In",
mesh,
field,
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockIndex),
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockIndex),
this->MultiBlockSpatialDecomposition.GlobalSize);
globalPointIndexStart,
pointDimensions,
globalPointDimensions);
bractFile << bractString << std::endl;
}
@ -461,18 +480,40 @@ vtkm::cont::DataSet ContourTreeUniformDistributed::DoExecute(const vtkm::cont::D
VTKM_CONT void ContourTreeUniformDistributed::PreExecute(
const vtkm::cont::PartitionedDataSet& input)
{
if (vtkm::filter::scalar_topology::internal::SpatialDecomposition::GetGlobalNumberOfBlocks(
input) != this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks())
// TODO/FIXME: The following may be too expensive for a "sanity" check as it
// requires global communication
auto globalNumberOfPartitions = input.GetGlobalNumberOfPartitions();
if (globalNumberOfPartitions < 2)
{
throw vtkm::cont::ErrorFilterExecution(
"Global number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
throw vtkm::cont::ErrorFilterExecution("ContourTreeUniformDistributed filter expects a "
"PartitionedDataSet with at least two partitions.");
}
if (this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks() !=
input.GetNumberOfPartitions())
if (this->BlocksPerDimension[0] != -1)
{
throw vtkm::cont::ErrorFilterExecution(
"Local number of blocks in MultiBlock dataset does not match the SpatialDecomposition");
if (this->BlocksPerDimension[1] < 1 || this->BlocksPerDimension[2] < 1)
{
throw vtkm::cont::ErrorFilterExecution("Invalid input BlocksPerDimension.");
}
if (globalNumberOfPartitions !=
this->BlocksPerDimension[0] * this->BlocksPerDimension[1] * this->BlocksPerDimension[2])
{
throw vtkm::cont::ErrorFilterExecution("Global number of blocks in data set does not match "
"expected value based on BlocksPerDimension");
}
if (this->LocalBlockIndices.GetNumberOfValues() != input.GetNumberOfPartitions())
{
throw vtkm::cont::ErrorFilterExecution("Local number of partitions in data set does not "
"match number of specified blocks indices.");
}
}
// Allocate vectors
this->LocalMeshes.resize(static_cast<std::size_t>(input.GetGlobalNumberOfPartitions()));
this->LocalContourTrees.resize(static_cast<std::size_t>(input.GetGlobalNumberOfPartitions()));
this->LocalBoundaryTrees.resize(static_cast<std::size_t>(input.GetGlobalNumberOfPartitions()));
this->LocalInteriorForests.resize(static_cast<std::size_t>(input.GetGlobalNumberOfPartitions()));
}
vtkm::cont::PartitionedDataSet ContourTreeUniformDistributed::DoExecutePartitions(
@ -546,15 +587,6 @@ VTKM_CONT void ContourTreeUniformDistributed::PostExecute(
vtkm::cont::Timer timer;
timer.Start();
// We are running in parallel and need to merge the contour tree in PostExecute
// TODO/FIXME: This filter should only be used in a parallel setting with more
// than one block. Is there a better way to enforce this? thrown an exception
// instead of an empty return? What is the appropriate exception?
if (this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks() == 1)
{
return;
}
auto field = // TODO/FIXME: Correct for more than one block per rank?
input.GetPartition(0).GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
@ -602,12 +634,15 @@ inline VTKM_CONT void ContourTreeUniformDistributed::ComputeVolumeMetric(
inputContourTreeMaster.foreach (
[&](DistributedContourTreeBlockData* currInBlock, const vtkmdiy::Master::ProxyWithLink&) {
vtkm::Id blockNo = currInBlock->LocalBlockNo;
const vtkm::cont::DataSet& currDS = hierarchicalTreeOutputDataSet[blockNo];
// The block size and origin may be modified during the FanIn so we need to use the
// size and origin from the original decomposition instead of looking it up in the currInBlock
auto currBlockSize =
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(blockNo);
auto currBlockOrigin =
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(blockNo);
vtkm::Id3 pointDimensions, globalPointDimensions, globalPointIndexStart;
currDS.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
pointDimensions,
globalPointDimensions,
globalPointIndexStart);
// NOTE: Use dummy link to make DIY happy. The dummy link is never used, since all
// communication is via RegularDecomposer, which sets up its own links. No need
@ -618,9 +653,9 @@ inline VTKM_CONT void ContourTreeUniformDistributed::ComputeVolumeMetric(
currInBlock->GlobalBlockId,
new HyperSweepBlock(blockNo,
currInBlock->GlobalBlockId,
currBlockOrigin,
currBlockSize,
this->MultiBlockSpatialDecomposition.GlobalSize,
globalPointIndexStart,
pointDimensions,
globalPointDimensions,
*currInBlock->HierarchicalAugmenter.AugmentedTree),
new vtkmdiy::Link());
});
@ -774,6 +809,7 @@ inline VTKM_CONT void ContourTreeUniformDistributed::ComputeVolumeMetric(
});
}
//-----------------------------------------------------------------------------
template <typename FieldType>
VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
@ -809,30 +845,32 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
// 1.1.2 Compute the gids for our local blocks
using RegularDecomposer = vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>;
const auto& spatialDecomp = this->MultiBlockSpatialDecomposition;
const auto numDims = spatialDecomp.NumberOfDimensions();
// ... compute division vector for global domain
RegularDecomposer::DivisionsVector diyDivisions(numDims);
for (vtkm::IdComponent d = 0; d < static_cast<vtkm::IdComponent>(numDims); ++d)
RegularDecomposer::DivisionsVector diyDivisions;
std::vector<int> vtkmdiyLocalBlockGids;
vtkmdiy::DiscreteBounds diyBounds(0);
if (this->BlocksPerDimension[0] == -1)
{
diyDivisions[d] = static_cast<int>(spatialDecomp.BlocksPerDimension[d]);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"BlocksPerDimension not set. Computing block indices "
"from information in CellSetStructured.");
diyBounds = vtkm::filter::scalar_topology::internal::ComputeBlockIndices(
input, diyDivisions, vtkmdiyLocalBlockGids);
}
// ... compute coordinates of local blocks
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
std::vector<int> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
else
{
RegularDecomposer::DivisionsVector diyCoords(static_cast<size_t>(numDims));
auto currentCoords = localBlockIndicesPortal.Get(bi);
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
diyCoords[d] = static_cast<int>(currentCoords[d]);
}
vtkmdiyLocalBlockGids[static_cast<size_t>(bi)] =
RegularDecomposer::coords_to_gid(diyCoords, diyDivisions);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"BlocksPerDimension set. Using information provided by caller.");
diyBounds =
vtkm::filter::scalar_topology::internal::ComputeBlockIndices(input,
this->BlocksPerDimension,
this->LocalBlockIndices,
diyDivisions,
vtkmdiyLocalBlockGids);
}
int numDims = diyBounds.min.dimension();
int globalNumberOfBlocks =
std::accumulate(diyDivisions.cbegin(), diyDivisions.cend(), 1, std::multiplies<int>{});
// Record time to compute the local block ids
timingsStream << " " << std::setw(38) << std::left << "Compute Block Ids and Local Links"
@ -840,16 +878,28 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
timer.Start();
// 1.1.3 Setup the block data for DIY and add it to master
// Note: globalPointDimensions is defined outside the loop since it is needed later.
// It may be set multiple times in the loop, but always to the same value.
vtkm::Id3 globalPointDimensions;
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
// Get the input block and associated cell set information
auto currBlock = input.GetPartition(static_cast<vtkm::Id>(bi));
vtkm::Id3 pointDimensions, globalPointIndexStart;
currBlock.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
pointDimensions,
globalPointDimensions,
globalPointIndexStart);
// Create the local data block structure and set extents
auto newBlock = new DistributedContourTreeBlockData();
// Copy global block id into the local data block for use in the hierarchical augmentation
newBlock->GlobalBlockId = vtkmdiyLocalBlockGids[bi];
newBlock->LocalBlockNo = bi;
newBlock->BlockOrigin = spatialDecomp.LocalBlockOrigins.ReadPortal().Get(bi);
newBlock->BlockSize = spatialDecomp.LocalBlockSizes.ReadPortal().Get(bi);
newBlock->BlockOrigin = globalPointIndexStart;
newBlock->BlockSize = pointDimensions;
// Save local tree information for fan out; TODO/FIXME: Try to avoid copy
newBlock->ContourTrees.push_back(this->LocalContourTrees[bi]);
@ -868,15 +918,10 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
auto transformedIndex = vtkm::cont::make_ArrayHandleTransform(
permutedSortOrder,
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
static_cast<vtkm::Id>(bi)),
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
static_cast<vtkm::Id>(bi)),
this->MultiBlockSpatialDecomposition.GlobalSize));
globalPointIndexStart, pointDimensions, globalPointDimensions));
vtkm::cont::Algorithm::Copy(transformedIndex, localGlobalMeshIndex);
// ... get data values
auto currBlock = input.GetPartition(static_cast<vtkm::Id>(bi));
auto currField =
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
vtkm::cont::ArrayHandle<FieldType> fieldData;
@ -942,16 +987,15 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
RegularDecomposer::BoolVector wrap(3, false);
RegularDecomposer::CoordinateVector ghosts(3, 1);
RegularDecomposer decomposer(static_cast<int>(numDims),
spatialDecomp.GetVTKmDIYBounds(),
static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()),
diyBounds,
globalNumberOfBlocks,
shareFace,
wrap,
ghosts,
diyDivisions);
// Define which blocks live on which rank so that vtkmdiy can manage them
vtkmdiy::DynamicAssigner assigner(
comm, static_cast<int>(size), static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
vtkmdiy::DynamicAssigner assigner(comm, static_cast<int>(size), globalNumberOfBlocks);
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
assigner.set_rank(static_cast<int>(rank), vtkmdiyLocalBlockGids[static_cast<size_t>(bi)]);
@ -984,7 +1028,7 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
timer.Start();
// 1.3 Perform fan-in reduction
const vtkm::worklet::contourtree_distributed::ComputeDistributedContourTreeFunctor<FieldType>
computeDistributedContourTreeFunctor(this->MultiBlockSpatialDecomposition.GlobalSize,
computeDistributedContourTreeFunctor(globalPointDimensions,
this->UseBoundaryExtremaOnly,
this->TimingsLogLevel,
this->TreeLogLevel);
@ -1061,17 +1105,22 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
grafter(&(this->LocalMeshes[static_cast<std::size_t>(blockData->LocalBlockNo)]),
blockData->ContourTrees[0],
&(blockData->InteriorForests[0]));
auto currBlock = input.GetPartition(blockData->LocalBlockNo);
vtkm::cont::DataSet currBlock = input.GetPartition(blockData->LocalBlockNo);
auto currField =
currBlock.GetField(this->GetActiveFieldName(), this->GetActiveFieldAssociation());
vtkm::cont::ArrayHandle<FieldType> fieldData;
vtkm::cont::ArrayCopy(currField.GetData(), fieldData);
vtkm::Id3 pointDimensions, globalPointIndexStart;
// globalPointDimensions already defined in parent scope
currBlock.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
pointDimensions,
globalPointDimensions,
globalPointIndexStart);
auto localToGlobalIdRelabeler = vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler(
this->MultiBlockSpatialDecomposition.LocalBlockOrigins.ReadPortal().Get(
blockData->LocalBlockNo),
this->MultiBlockSpatialDecomposition.LocalBlockSizes.ReadPortal().Get(
blockData->LocalBlockNo),
this->MultiBlockSpatialDecomposition.GlobalSize);
globalPointIndexStart, pointDimensions, globalPointDimensions);
grafter.GraftInteriorForests(
0, blockData->HierarchicalTree, fieldData, &localToGlobalIdRelabeler);
@ -1155,9 +1204,30 @@ VTKM_CONT void ContourTreeUniformDistributed::DoPostExecute(
// Add the information to the output data set
blockHierarchcialTree.AddToVTKMDataSet(hierarchicalTreeOutputDataSet[blockData->LocalBlockNo]);
// Save information required to set up DIY
vtkm::cont::ArrayHandle<vtkm::Id> vtkmGlobalBlockIdAH;
vtkmGlobalBlockIdAH.Allocate(1);
auto vtkmGlobalBlockIdWP = vtkmGlobalBlockIdAH.WritePortal();
vtkmGlobalBlockIdWP.Set(0, blockData->GlobalBlockId);
vtkm::cont::Field vtkmGlobalBlockIdField(
"vtkmGlobalBlockId", vtkm::cont::Field::Association::WholeMesh, vtkmGlobalBlockIdAH);
hierarchicalTreeOutputDataSet[blockData->LocalBlockNo].AddField(vtkmGlobalBlockIdField);
vtkm::cont::ArrayHandle<vtkm::Id> vtkmBlocksPerDimensionAH;
vtkmBlocksPerDimensionAH.Allocate(3);
auto vtkmBlocksPerDimensionWP = vtkmBlocksPerDimensionAH.WritePortal();
vtkmBlocksPerDimensionWP.Set(0, this->BlocksPerDimension[0]);
vtkmBlocksPerDimensionWP.Set(1, this->BlocksPerDimension[1]);
vtkmBlocksPerDimensionWP.Set(2, this->BlocksPerDimension[2]);
vtkm::cont::Field vtkmBlocksPerDimensionField("vtkmBlocksPerDimension",
vtkm::cont::Field::Association::WholeMesh,
vtkmBlocksPerDimensionAH);
hierarchicalTreeOutputDataSet[blockData->LocalBlockNo].AddField(vtkmBlocksPerDimensionField);
// Copy cell set from input data set. This is mainly to ensure that the output data set
// has a defined cell set. Without one, serialization for DIY does not work properly.
// Having the extents of the input data set may also help in other use cases.
// For example, the ComputeVolume method gets information from this cell set as will
// the branch decomposition filter.
hierarchicalTreeOutputDataSet[blockData->LocalBlockNo].SetCellSet(
input.GetPartition(blockData->LocalBlockNo).GetCellSet());

@ -56,7 +56,6 @@
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/filter/scalar_topology/internal/SpatialDecomposition.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/ContourTree.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/DataSetMesh.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_distributed/BoundaryTree.h>
@ -113,14 +112,20 @@ public:
/// @param[in] treeLogLevel Set the vtkm::cont:LogLevel to be used to record metadata information
/// about the various trees computed as part of the hierarchical contour tree compute
VTKM_CONT
ContourTreeUniformDistributed(
vtkm::Id3 blocksPerDim, // TODO/FIXME: Possibly pass SpatialDecomposition object instead
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
vtkm::cont::LogLevel timingsLogLevel = vtkm::cont::LogLevel::Perf,
vtkm::cont::LogLevel treeLogLevel = vtkm::cont::LogLevel::Info);
VTKM_DEPRECATED(
1.9,
"Use default constructor and set PointSize, GlobalPointIndexStart, and GlobalPointSize in "
"CellSetStructured. Optionally use `SetBlockIndices` accessor (if information is available).")
ContourTreeUniformDistributed(vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
vtkm::cont::LogLevel timingsLogLevel = vtkm::cont::LogLevel::Perf,
vtkm::cont::LogLevel treeLogLevel = vtkm::cont::LogLevel::Info);
ContourTreeUniformDistributed(vtkm::cont::LogLevel timingsLogLevel = vtkm::cont::LogLevel::Perf,
vtkm::cont::LogLevel treeLogLevel = vtkm::cont::LogLevel::Info);
VTKM_CONT void SetUseBoundaryExtremaOnly(bool useBoundaryExtremaOnly)
{
@ -141,6 +146,13 @@ public:
this->AugmentHierarchicalTree = augmentHierarchicalTree;
}
VTKM_CONT void SetBlockIndices(vtkm::Id3 blocksPerDim,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices)
{
this->BlocksPerDimension = blocksPerDim;
vtkm::cont::ArrayCopy(localBlockIndices, this->LocalBlockIndices);
}
VTKM_CONT bool GetAugmentHierarchicalTree() { return this->AugmentHierarchicalTree; }
VTKM_CONT void SetSaveDotFiles(bool saveDotFiles) { this->SaveDotFiles = saveDotFiles; }
@ -213,8 +225,11 @@ private:
/// Log level to be used for outputting metadata about the trees. Default is vtkm::cont::LogLevel::Info
vtkm::cont::LogLevel TreeLogLevel = vtkm::cont::LogLevel::Info;
/// Information about the spatial decomposition
vtkm::filter::scalar_topology::internal::SpatialDecomposition MultiBlockSpatialDecomposition;
/// Information about block decomposition TODO/FIXME: Remove need for this information
// ... Number of blocks along each dimension
vtkm::Id3 BlocksPerDimension;
// ... Index of the local blocks in x,y,z, i.e., in i,j,k mesh coordinates
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockIndices;
/// Intermediate results (one per local data block)...
/// ... local mesh information needed at end of fan out
@ -240,28 +255,23 @@ class VTKM_DEPRECATED(1.8, "Use vtkm::filter::scalar_topology::ContourTreeUnifor
using scalar_topology::ContourTreeUniformDistributed::ContourTreeUniformDistributed;
ContourTreeUniformDistributed(vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
vtkm::Id3,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
bool useBoundaryExtremaOnly = true,
bool useMarchingCubes = false,
bool augmentHierarchicalTree = false,
bool saveDotFiles = false,
vtkm::cont::LogLevel timingsLogLevel = vtkm::cont::LogLevel::Perf,
vtkm::cont::LogLevel treeLogLevel = vtkm::cont::LogLevel::Info)
: vtkm::filter::scalar_topology::ContourTreeUniformDistributed(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes,
timingsLogLevel,
treeLogLevel)
: vtkm::filter::scalar_topology::ContourTreeUniformDistributed(timingsLogLevel, treeLogLevel)
{
this->SetUseBoundaryExtremaOnly(useBoundaryExtremaOnly);
this->SetUseMarchingCubes(useMarchingCubes);
this->SetAugmentHierarchicalTree(augmentHierarchicalTree);
this->SetSaveDotFiles(saveDotFiles);
this->SetBlockIndices(blocksPerDim, localBlockIndices);
this->SetOutputFieldName("resultData");
}
};

@ -36,16 +36,11 @@ namespace scalar_topology
// not need to pass it sperately (or check if it can already be derived from
// information stored in PartitionedDataSet)
VTKM_CONT DistributedBranchDecompositionFilter::DistributedBranchDecompositionFilter(
vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes)
: MultiBlockSpatialDecomposition(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes)
vtkm::Id3,
vtkm::Id3,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&)
{
}
@ -80,52 +75,59 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
BranchDecompositionBlock::Destroy);
timingsStream << " " << std::setw(60) << std::left
<< "Create DIY Master (Branch Decomposition)"
<< "Create DIY Master and Assigner (Branch Decomposition)"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
// Compute global ids (gids) for our local blocks
using RegularDecomposer = vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>;
int globalNumberOfBlocks =
static_cast<int>(this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks());
int numDims = static_cast<int>(this->MultiBlockSpatialDecomposition.NumberOfDimensions());
// TODO/FIXME: Is there a better way to set this up?
auto firstDS = input.GetPartition(0);
vtkm::Id3 firstPointDimensions, firstGlobalPointDimensions, firstGlobalPointIndexStart;
firstDS.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
firstPointDimensions,
firstGlobalPointDimensions,
firstGlobalPointIndexStart);
int numDims = firstGlobalPointDimensions[2] > 1 ? 3 : 2;
auto vtkmBlocksPerDimensionRP = input.GetPartition(0)
.GetField("vtkmBlocksPerDimension")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()
.ReadPortal();
// ... compute division vector for global domain
using RegularDecomposer = vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>;
RegularDecomposer::DivisionsVector diyDivisions(numDims);
vtkmdiy::DiscreteBounds diyBounds(numDims);
int globalNumberOfBlocks = 1;
for (vtkm::IdComponent d = 0; d < static_cast<vtkm::IdComponent>(numDims); ++d)
{
diyDivisions[d] = static_cast<int>(this->MultiBlockSpatialDecomposition.BlocksPerDimension[d]);
}
// ... compute coordinates of local blocks
std::vector<int> vtkmdiyLocalBlockGids(static_cast<size_t>(input.GetNumberOfPartitions()));
auto localBlockIndicesPortal =
this->MultiBlockSpatialDecomposition.LocalBlockIndices.ReadPortal();
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
RegularDecomposer::DivisionsVector diyCoords(static_cast<size_t>(numDims));
auto currentCoords = localBlockIndicesPortal.Get(bi);
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
diyCoords[d] = static_cast<int>(currentCoords[d]);
}
vtkmdiyLocalBlockGids[static_cast<size_t>(bi)] =
RegularDecomposer::coords_to_gid(diyCoords, diyDivisions);
diyDivisions[d] = static_cast<int>(vtkmBlocksPerDimensionRP.Get(d));
globalNumberOfBlocks *= diyDivisions[d];
diyBounds.min[d] = 0;
diyBounds.max[d] = static_cast<int>(firstGlobalPointDimensions[d]);
}
// Record time to compute the local block ids
timingsStream << " " << std::setw(60) << std::left
<< "Compute Block Ids and Local Links (Branch Decomposition)"
<< "Get DIY Information (Branch Decomposition)"
<< ": " << timer.GetElapsedTime() << " seconds" << std::endl;
timer.Start();
// Initialize branch decomposition computation from data in PartitionedDataSet blocks
vtkmdiy::DynamicAssigner assigner(comm, size, globalNumberOfBlocks);
for (vtkm::Id localBlockIndex = 0; localBlockIndex < input.GetNumberOfPartitions();
++localBlockIndex)
{
int globalBlockId = vtkmdiyLocalBlockGids[localBlockIndex];
const vtkm::cont::DataSet& ds = input.GetPartition(localBlockIndex);
int globalBlockId = static_cast<int>(
vtkm::cont::ArrayGetValue(0,
ds.GetField("vtkmGlobalBlockId")
.GetData()
.AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>()));
BranchDecompositionBlock* newBlock =
new BranchDecompositionBlock(localBlockIndex, globalBlockId, ds);
// NOTE: Use dummy link to make DIY happy. The dummy link is never used, since all
@ -134,6 +136,9 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
// NOTE: Since we passed a "Destroy" function to DIY master, it will own the local data
// blocks and delete them when done.
branch_decomposition_master.add(globalBlockId, newBlock, new vtkmdiy::Link());
// Tell assigner that this block lives on this rank so that DIY can manage blocks
assigner.set_rank(rank, globalBlockId);
}
// Log time to copy the data to the HyperSweepBlock data objects
@ -146,19 +151,15 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
RegularDecomposer::BoolVector wrap(3, false);
RegularDecomposer::CoordinateVector ghosts(3, 1);
RegularDecomposer decomposer(numDims,
this->MultiBlockSpatialDecomposition.GetVTKmDIYBounds(),
diyBounds,
static_cast<int>(globalNumberOfBlocks),
shareFace,
wrap,
ghosts,
diyDivisions);
// Define which blocks live on which rank so that vtkmdiy can manage them
vtkmdiy::DynamicAssigner assigner(comm, size, globalNumberOfBlocks);
for (vtkm::Id bi = 0; bi < input.GetNumberOfPartitions(); bi++)
{
assigner.set_rank(rank, vtkmdiyLocalBlockGids[static_cast<size_t>(bi)]);
}
timingsStream << " " << std::setw(60) << std::left
@ -196,7 +197,7 @@ VTKM_CONT vtkm::cont::PartitionedDataSet DistributedBranchDecompositionFilter::D
ds.GetField("DependentVolume").GetData().AsArrayHandle<vtkm::cont::ArrayHandle<vtkm::Id>>();
// Get global size and compute total volume from it
const auto& globalSize = this->MultiBlockSpatialDecomposition.GlobalSize;
const auto& globalSize = firstGlobalPointDimensions;
vtkm::Id totalVolume = globalSize[0] * globalSize[1] * globalSize[2];
// Compute local best up and down paths by volume

@ -45,8 +45,6 @@
#include <vtkm/filter/NewFilterField.h>
#include <vtkm/filter/scalar_topology/vtkm_filter_scalar_topology_export.h>
#include <vtkm/filter/scalar_topology/internal/SpatialDecomposition.h>
namespace vtkm
{
namespace filter
@ -59,20 +57,17 @@ class VTKM_FILTER_SCALAR_TOPOLOGY_EXPORT DistributedBranchDecompositionFilter
: public vtkm::filter::NewFilter
{
public:
VTKM_CONT DistributedBranchDecompositionFilter(
vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes);
VTKM_CONT DistributedBranchDecompositionFilter() = default;
VTKM_CONT DistributedBranchDecompositionFilter(vtkm::Id3,
vtkm::Id3,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&,
const vtkm::cont::ArrayHandle<vtkm::Id3>&);
private:
VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet&) override;
VTKM_CONT vtkm::cont::PartitionedDataSet DoExecutePartitions(
const vtkm::cont::PartitionedDataSet& inData) override;
/// Information about the spatial decomposition
vtkm::filter::scalar_topology::internal::SpatialDecomposition MultiBlockSpatialDecomposition;
};
} // namespace scalar_topology

@ -10,8 +10,8 @@
set(headers
BranchDecompositionBlock.h
ComputeBlockIndices.h
ComputeDistributedBranchDecompositionFunctor.h
SpatialDecomposition.h
)
#-----------------------------------------------------------------------------

@ -0,0 +1,255 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#include <algorithm>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/DataSet.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/filter/scalar_topology/internal/ComputeBlockIndices.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/contourtreemesh/CopyIntoCombinedArrayWorklet.h>
namespace // anonymous namespace for local helper classes
{
struct OriginsBlock
{
std::vector<int> Origins;
OriginsBlock(const std::vector<int>& origins)
: Origins(origins)
{
}
static void Destroy(void* b) { delete static_cast<OriginsBlock*>(b); }
};
struct MergeOriginsFunctor
{
void operator()(OriginsBlock* b,
const vtkmdiy::ReduceProxy& rp, // communication proxy
const vtkmdiy::RegularSwapPartners& // partners of the current block (unused)
) const
{
const auto selfid = rp.gid();
std::vector<int> incoming;
rp.incoming(incoming);
for (const int ingid : incoming)
{
if (ingid != selfid)
{
std::vector<int> incoming_origins;
rp.dequeue(ingid, incoming_origins);
std::vector<int> merged_origins;
std::merge(incoming_origins.begin(),
incoming_origins.end(),
b->Origins.begin(),
b->Origins.end(),
std::inserter(merged_origins, merged_origins.begin()));
auto last = std::unique(merged_origins.begin(), merged_origins.end());
merged_origins.erase(last, merged_origins.end());
std::swap(merged_origins, b->Origins);
}
}
for (int cc = 0; cc < rp.out_link().size(); ++cc)
{
auto target = rp.out_link().target(cc);
if (target.gid != selfid)
{
rp.enqueue(target, b->Origins);
}
}
}
};
}
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
namespace internal
{
VTKM_CONT vtkmdiy::DiscreteBounds ComputeBlockIndices(const vtkm::cont::PartitionedDataSet& input,
DiscreteBoundsDivisionVector& diyDivisions,
std::vector<int>& diyLocalBlockGids)
{
auto firstDS = input.GetPartition(0);
vtkm::Id3 dummy1, firstGlobalPointDimensions, dummy2;
firstDS.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
dummy1,
firstGlobalPointDimensions,
dummy2);
int numDims = firstGlobalPointDimensions[2] > 1 ? 3 : 2;
diyDivisions.clear();
vtkmdiy::DiscreteBounds diyBounds(numDims);
std::vector<DiscreteBoundsDivisionVector> diyBlockCoords(input.GetNumberOfPartitions());
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
// Set bounds for this dimension
diyBounds.min[d] = 0;
diyBounds.max[d] = static_cast<int>(firstGlobalPointDimensions[d]);
// Get the list of origins along current coordinate axis
std::vector<int> local_origins;
for (vtkm::Id ds_no = 0; ds_no < input.GetNumberOfPartitions(); ++ds_no)
{
vtkm::Id3 globalPointIndexStart;
input.GetPartition(ds_no)
.GetCellSet()
.CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
dummy1,
dummy2,
globalPointIndexStart);
local_origins.push_back(static_cast<int>(globalPointIndexStart[d]));
}
// Sort and remove duplicates
OriginsBlock* origins_block = new OriginsBlock(local_origins);
std::sort(origins_block->Origins.begin(), origins_block->Origins.end());
auto last = std::unique(origins_block->Origins.begin(), origins_block->Origins.end());
origins_block->Origins.erase(last, origins_block->Origins.end());
// Create global list of origins across all ranks
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
auto rank = comm.rank();
auto size = comm.size();
vtkmdiy::Master master(comm, 1, -1, 0, OriginsBlock::Destroy);
master.add(rank, origins_block, new vtkmdiy::Link);
vtkmdiy::ContiguousAssigner assigner(size, size);
vtkmdiy::DiscreteBounds bounds(1);
bounds.min[0] = 0;
bounds.max[0] = size - 1;
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds> decomposer(1, bounds, size);
vtkmdiy::RegularSwapPartners partners(decomposer, 2, true);
vtkmdiy::reduce(master, assigner, partners, MergeOriginsFunctor{});
// Number of blocks/divisions along axis is number of unique origins along this axis
diyDivisions.push_back(static_cast<int>(origins_block->Origins.size()));
// Block index aling this axis is the index of the origin in that list
for (vtkm::Id ds_no = 0; ds_no < input.GetNumberOfPartitions(); ++ds_no)
{
diyBlockCoords[ds_no].push_back(static_cast<int>(std::find(origins_block->Origins.begin(),
origins_block->Origins.end(),
local_origins[ds_no]) -
origins_block->Origins.begin()));
}
}
// Compute global block IDs
diyLocalBlockGids.clear();
for (vtkm::Id ds_no = 0; ds_no < input.GetNumberOfPartitions(); ++ds_no)
{
diyLocalBlockGids.push_back(vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>::coords_to_gid(
diyBlockCoords[ds_no], diyDivisions));
}
return diyBounds;
}
VTKM_CONT vtkmdiy::DiscreteBounds ComputeBlockIndices(
const vtkm::cont::PartitionedDataSet& input,
vtkm::Id3 blocksPerDim,
const vtkm::cont::ArrayHandle<vtkm::Id3>& blockIndices,
DiscreteBoundsDivisionVector& diyDivisions,
std::vector<int>& diyLocalBlockGids)
{
auto firstDS = input.GetPartition(0);
vtkm::Id3 dummy1, firstGlobalPointDimensions, dummy2;
firstDS.GetCellSet().CastAndCallForTypes<VTKM_DEFAULT_CELL_SET_LIST_STRUCTURED>(
vtkm::worklet::contourtree_augmented::GetLocalAndGlobalPointDimensions(),
dummy1,
firstGlobalPointDimensions,
dummy2);
int numDims = firstGlobalPointDimensions[2] > 1 ? 3 : 2;
diyDivisions.clear();
vtkmdiy::DiscreteBounds diyBounds(numDims);
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
// Set bounds for this dimension
diyBounds.min[d] = 0;
diyBounds.max[d] = static_cast<int>(firstGlobalPointDimensions[d]);
diyDivisions.push_back(static_cast<int>(blocksPerDim[d]));
}
// Compute global block IDs
diyLocalBlockGids.clear();
auto blockIndicesPortal = blockIndices.ReadPortal();
for (vtkm::Id ds_no = 0; ds_no < input.GetNumberOfPartitions(); ++ds_no)
{
auto currBlockIndices = blockIndicesPortal.Get(ds_no);
DiscreteBoundsDivisionVector diyBlockCoords(numDims);
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
diyBlockCoords[d] = static_cast<int>(currBlockIndices[d]);
}
diyLocalBlockGids.push_back(vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>::coords_to_gid(
diyBlockCoords, diyDivisions));
}
return diyBounds;
}
} // namespace internal
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm

@ -0,0 +1,98 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_internal_ComputeBlockIndices_h_
#define vtk_m_filter_scalar_topology_internal_ComputeBlockIndices_h_
#include <vector>
#include <vtkm/Types.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/PartitionedDataSet.h>
// DIY includes
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/Configure.h>
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
namespace internal
{
using DiscreteBoundsDivisionVector =
vtkmdiy::RegularDecomposer<vtkmdiy::DiscreteBounds>::DivisionsVector;
VTKM_CONT vtkmdiy::DiscreteBounds ComputeBlockIndices(const vtkm::cont::PartitionedDataSet& input,
DiscreteBoundsDivisionVector& diyDivisions,
std::vector<int>& diyLocalBlockGids);
VTKM_CONT vtkmdiy::DiscreteBounds ComputeBlockIndices(
const vtkm::cont::PartitionedDataSet& input,
vtkm::Id3 blocksPerDim,
const vtkm::cont::ArrayHandle<vtkm::Id3>& blockIndices,
DiscreteBoundsDivisionVector& diyDivisions,
std::vector<int>& diyLocalBlockGids);
} // namespace internal
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif

@ -1,172 +0,0 @@
//============================================================================
// Copyright (c) Kitware, Inc.
// All rights reserved.
// See LICENSE.txt 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.
//============================================================================
// Copyright (c) 2018, The Regents of the University of California, through
// Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
// from the U.S. Dept. of Energy). All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// (1) Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// (2) Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// (3) Neither the name of the University of California, Lawrence Berkeley National
// Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
//
//=============================================================================
//
// This code is an extension of the algorithm presented in the paper:
// Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
// Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
// Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
// (LDAV), October 2016, Baltimore, Maryland.
//
// The PPP2 algorithm and software were jointly developed by
// Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
// Oliver Ruebel (LBNL)
//==============================================================================
#ifndef vtk_m_filter_scalar_topology_internal_SpatialDecomposition_h
#define vtk_m_filter_scalar_topology_internal_SpatialDecomposition_h
#include <vtkm/Types.h>
#include <vtkm/cont/BoundsCompute.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
#include <vtkm/cont/EnvironmentTracker.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE
#include <vtkm/thirdparty/diy/diy.h>
VTKM_THIRDPARTY_POST_INCLUDE
// clang-format on
namespace vtkm
{
namespace filter
{
namespace scalar_topology
{
namespace internal
{
// --- Helper class to store the spatial decomposition defined by the PartitionedDataSet input data
class SpatialDecomposition
{
public:
VTKM_CONT
SpatialDecomposition(vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes)
: BlocksPerDimension(blocksPerDim)
, GlobalSize(globalSize)
, LocalBlockIndices(localBlockIndices)
, LocalBlockOrigins(localBlockOrigins)
, LocalBlockSizes(localBlockSizes)
{
}
inline vtkmdiy::DiscreteBounds GetVTKmDIYBounds() const
{
if (this->NumberOfDimensions() == 2)
{
vtkmdiy::DiscreteBounds domain(2);
domain.min[0] = domain.min[1] = 0;
domain.max[0] = static_cast<int>(this->GlobalSize[0]);
domain.max[1] = static_cast<int>(this->GlobalSize[1]);
return domain;
}
else
{
vtkmdiy::DiscreteBounds domain(3);
domain.min[0] = domain.min[1] = domain.min[2] = 0;
domain.max[0] = static_cast<int>(this->GlobalSize[0]);
domain.max[1] = static_cast<int>(this->GlobalSize[1]);
domain.max[2] = static_cast<int>(this->GlobalSize[2]);
return domain;
}
}
inline vtkm::Id NumberOfDimensions() const { return GlobalSize[2] > 1 ? 3 : 2; }
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return BlocksPerDimension[0] * BlocksPerDimension[1] * BlocksPerDimension[2];
}
inline vtkm::Id GetLocalNumberOfBlocks() const { return LocalBlockSizes.GetNumberOfValues(); }
inline static vtkm::Bounds GetGlobalBounds(const vtkm::cont::PartitionedDataSet& input)
{
// Get the spatial bounds of a multi -block data set
vtkm::Bounds bounds = vtkm::cont::BoundsGlobalCompute(input);
return bounds;
}
inline static vtkm::Bounds GetLocalBounds(const vtkm::cont::PartitionedDataSet& input)
{
// Get the spatial bounds of a multi -block data set
vtkm::Bounds bounds = vtkm::cont::BoundsCompute(input);
return bounds;
}
inline static vtkm::Id GetGlobalNumberOfBlocks(const vtkm::cont::PartitionedDataSet& input)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
vtkm::Id localSize = input.GetNumberOfPartitions();
vtkm::Id globalSize = 0;
#ifdef VTKM_ENABLE_MPI
vtkmdiy::mpi::all_reduce(comm, localSize, globalSize, std::plus<vtkm::Id>{});
#else
globalSize = localSize;
#endif
return globalSize;
}
// Number of blocks along each dimension
vtkm::Id3 BlocksPerDimension;
// Size of the global mesh
vtkm::Id3 GlobalSize;
// Index of the local blocks in x,y,z, i.e., in i,j,k mesh coordinates
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockIndices;
// Origin of the local blocks in mesh index space
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockOrigins;
// Size of each local block in x, y,z
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockSizes;
};
} // internal
} // namespace scalar_topology
} // namespace filter
} // namespace vtkm
#endif

@ -203,12 +203,22 @@ inline vtkm::cont::DataSet CreateSubDataSet(const vtkm::cont::DataSet& ds,
{
vtkm::Id2 dimensions{ blockSize[0], blockSize[1] };
vtkm::cont::DataSet dataSet = dsb.Create(dimensions);
vtkm::cont::CellSetStructured<2> cellSet;
cellSet.SetPointDimensions(dimensions);
cellSet.SetGlobalPointDimensions(vtkm::Id2{ globalSize[0], globalSize[1] });
cellSet.SetGlobalPointIndexStart(vtkm::Id2{ blockOrigin[0], blockOrigin[1] });
dataSet.SetCellSet(cellSet);
dataSet.AddField(permutedField);
return dataSet;
}
else
{
vtkm::cont::DataSet dataSet = dsb.Create(blockSize);
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions(blockSize);
cellSet.SetGlobalPointDimensions(globalSize);
cellSet.SetGlobalPointIndexStart(blockOrigin);
dataSet.SetCellSet(cellSet);
dataSet.AddField(permutedField);
return dataSet;
}
@ -241,7 +251,8 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
int numberOfRanks,
bool augmentHierarchicalTree,
bool computeHierarchicalVolumetricBranchDecomposition,
vtkm::Id3& globalSize)
vtkm::Id3& globalSize,
bool passBlockIndices = true)
{
// Get dimensions of data set
vtkm::cont::CastAndCall(
@ -267,15 +278,9 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
// Created partitioned (split) data set
vtkm::cont::PartitionedDataSet pds;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockIndices;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockOrigins;
vtkm::cont::ArrayHandle<vtkm::Id3> localBlockSizes;
localBlockIndices.Allocate(blocksOnThisRank);
localBlockOrigins.Allocate(blocksOnThisRank);
localBlockSizes.Allocate(blocksOnThisRank);
auto localBlockIndicesPortal = localBlockIndices.WritePortal();
auto localBlockOriginsPortal = localBlockOrigins.WritePortal();
auto localBlockSizesPortal = localBlockSizes.WritePortal();
for (vtkm::Id blockNo = 0; blockNo < blocksOnThisRank; ++blockNo)
{
@ -283,20 +288,17 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
std::tie(blockIndex, blockOrigin, blockSize) =
ComputeBlockExtents(globalSize, blocksPerAxis, startBlockNo + blockNo);
pds.AppendPartition(CreateSubDataSet(ds, blockOrigin, blockSize, fieldName));
localBlockOriginsPortal.Set(blockNo, blockOrigin);
localBlockSizesPortal.Set(blockNo, blockSize);
localBlockIndicesPortal.Set(blockNo, blockIndex);
}
// Run the contour tree analysis
vtkm::filter::scalar_topology::ContourTreeUniformDistributed filter(
blocksPerAxis,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes,
vtkm::cont::LogLevel::UserVerboseLast,
vtkm::cont::LogLevel::UserVerboseLast);
vtkm::cont::LogLevel::UserVerboseLast, vtkm::cont::LogLevel::UserVerboseLast);
if (passBlockIndices)
{
filter.SetBlockIndices(blocksPerAxis, localBlockIndices);
}
filter.SetUseMarchingCubes(useMarchingCubes);
// Freudenthal: Only use boundary extrema; MC: use all points on boundary
@ -310,8 +312,7 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
{
using vtkm::filter::scalar_topology::DistributedBranchDecompositionFilter;
DistributedBranchDecompositionFilter bd_filter(
blocksPerAxis, globalSize, localBlockIndices, localBlockOrigins, localBlockSizes);
DistributedBranchDecompositionFilter bd_filter;
result = bd_filter.Execute(result);
}
@ -387,7 +388,8 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
int rank = 0,
int numberOfRanks = 1,
bool augmentHierarchicalTree = false,
bool computeHierarchicalVolumetricBranchDecomposition = false)
bool computeHierarchicalVolumetricBranchDecomposition = false,
bool passBlockIndices = true)
{
vtkm::Id3 globalSize;
@ -399,7 +401,8 @@ inline vtkm::cont::PartitionedDataSet RunContourTreeDUniformDistributed(
numberOfRanks,
augmentHierarchicalTree,
computeHierarchicalVolumetricBranchDecomposition,
globalSize);
globalSize,
passBlockIndices);
}
inline void TestContourTreeUniformDistributed8x9(int nBlocks, int rank = 0, int size = 1)
@ -575,7 +578,8 @@ inline void TestContourTreeFile(std::string ds_filename,
int rank = 0,
int size = 1,
bool augmentHierarchicalTree = false,
bool computeHierarchicalVolumetricBranchDecomposition = false)
bool computeHierarchicalVolumetricBranchDecomposition = false,
bool passBlockIndices = true)
{
if (rank == 0)
{
@ -611,7 +615,8 @@ inline void TestContourTreeFile(std::string ds_filename,
size,
augmentHierarchicalTree,
computeHierarchicalVolumetricBranchDecomposition,
globalSize);
globalSize,
passBlockIndices);
if (rank == 0)
{

@ -112,6 +112,16 @@ public:
1,
true,
false);
TestContourTreeFile(Testing::DataPath("rectilinear/vanc.vtk"),
"var",
Testing::RegressionImagePath("vanc.augment_hierarchical_tree.ct_txt"),
4,
false,
0,
1,
true,
false,
false);
}
};
}

@ -328,6 +328,47 @@ struct GetPointDimensions
}
};
struct GetLocalAndGlobalPointDimensions
{
void operator()(const vtkm::cont::CellSetStructured<2>& cells,
vtkm::Id3& pointDimensions,
vtkm::Id3& globalPointDimensions,
vtkm::Id3& globalPointIndexStart) const
{
vtkm::Id2 pointDimensions2D = cells.GetPointDimensions();
pointDimensions[0] = pointDimensions2D[0];
pointDimensions[1] = pointDimensions2D[1];
pointDimensions[2] = 1;
vtkm::Id2 globalPointDimensions2D = cells.GetGlobalPointDimensions();
globalPointDimensions[0] = globalPointDimensions2D[0];
globalPointDimensions[1] = globalPointDimensions2D[1];
globalPointDimensions[2] = 1;
vtkm::Id2 pointIndexStart2D = cells.GetGlobalPointIndexStart();
globalPointIndexStart[0] = pointIndexStart2D[0];
globalPointIndexStart[1] = pointIndexStart2D[1];
globalPointIndexStart[2] = 0;
}
void operator()(const vtkm::cont::CellSetStructured<3>& cells,
vtkm::Id3& pointDimensions,
vtkm::Id3& globalPointDimensions,
vtkm::Id3& globalPointIndexStart) const
{
pointDimensions = cells.GetPointDimensions();
globalPointDimensions = cells.GetGlobalPointDimensions();
globalPointIndexStart = cells.GetGlobalPointIndexStart();
}
//@}
/// Raise ErrorBadValue if the input cell set is not a vtkm::cont::CellSetStructured<2> or <3>
template <typename T>
void operator()(const T&, vtkm::Id3&, vtkm::Id3&, vtkm::Id3&) const
{
throw vtkm::cont::ErrorBadValue("Expected 2D or 3D structured cell cet! ");
}
};
} // namespace contourtree_augmented
} // worklet
} // vtkm

@ -53,15 +53,12 @@
#ifndef vtk_m_worklet_contourtree_distributed_multiblockcontourtreehelper_h
#define vtk_m_worklet_contourtree_distributed_multiblockcontourtreehelper_h
#include <vtkm/filter/scalar_topology/internal/SpatialDecomposition.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/Types.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
#include <vtkm/Types.h>
#include <vtkm/cont/BoundsCompute.h>
#include <vtkm/cont/BoundsGlobalCompute.h>
//#include <vtkm/cont/AssignerPartitionedDataSet.h>
#include <vtkm/cont/ErrorFilterExecution.h>
#include <vtkm/cont/PartitionedDataSet.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/data_set_mesh/IdRelabeler.h>
@ -79,19 +76,21 @@ class MultiBlockContourTreeHelper
public:
VTKM_CONT
MultiBlockContourTreeHelper(vtkm::Id3 blocksPerDim,
vtkm::Id3 globalSize,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockOrigins,
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockSizes)
: MultiBlockSpatialDecomposition(blocksPerDim,
globalSize,
localBlockIndices,
localBlockOrigins,
localBlockSizes)
const vtkm::cont::ArrayHandle<vtkm::Id3>& localBlockIndices)
: BlocksPerDimension(blocksPerDim)
, LocalBlockIndices(localBlockIndices)
, LocalContourTrees(static_cast<size_t>(localBlockIndices.GetNumberOfValues()))
, LocalSortOrders(static_cast<size_t>(localBlockIndices.GetNumberOfValues()))
{
}
VTKM_CONT
MultiBlockContourTreeHelper(const vtkm::cont::PartitionedDataSet& input)
: BlocksPerDimension(-1, -1, -1)
, LocalBlockIndices()
, LocalContourTrees(static_cast<size_t>(input.GetNumberOfPartitions()))
, LocalSortOrders(static_cast<size_t>(input.GetNumberOfPartitions()))
{
vtkm::Id localNumBlocks = this->GetLocalNumberOfBlocks();
LocalContourTrees.resize(static_cast<std::size_t>(localNumBlocks));
LocalSortOrders.resize(static_cast<std::size_t>(localNumBlocks));
}
VTKM_CONT
@ -118,25 +117,12 @@ public:
inline vtkm::Id GetLocalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetLocalNumberOfBlocks();
return static_cast<vtkm::Id>(this->LocalContourTrees.size());
}
inline vtkm::Id GetGlobalNumberOfBlocks() const
{
return this->MultiBlockSpatialDecomposition.GetGlobalNumberOfBlocks();
}
inline static vtkm::Id GetGlobalNumberOfBlocks(const vtkm::cont::PartitionedDataSet& input)
{
auto comm = vtkm::cont::EnvironmentTracker::GetCommunicator();
vtkm::Id localSize = input.GetNumberOfPartitions();
vtkm::Id globalSize = 0;
#ifdef VTKM_ENABLE_MPI
vtkmdiy::mpi::all_reduce(comm, localSize, globalSize, std::plus<vtkm::Id>{});
#else
globalSize = localSize;
#endif
return globalSize;
return this->BlocksPerDimension[0] * this->BlocksPerDimension[1] * this->BlocksPerDimension[2];
}
// Used to compute the local contour tree mesh in after DoExecute. I.e., the function is
@ -198,7 +184,8 @@ public:
}
}
vtkm::filter::scalar_topology::internal::SpatialDecomposition MultiBlockSpatialDecomposition;
vtkm::Id3 BlocksPerDimension;
vtkm::cont::ArrayHandle<vtkm::Id3> LocalBlockIndices;
std::vector<vtkm::worklet::contourtree_augmented::ContourTree> LocalContourTrees;
std::vector<vtkm::worklet::contourtree_augmented::IdArrayType> LocalSortOrders;
}; // end MultiBlockContourTreeHelper

@ -37,15 +37,24 @@ public:
VTKM_EXEC_CONT
void SetPointDimensions(vtkm::Id dimensions) { this->PointDimensions = dimensions; }
VTKM_EXEC_CONT
void SetGlobalPointDimensions(vtkm::Id dimensions) { this->GlobalPointDimensions = dimensions; }
VTKM_EXEC_CONT
void SetGlobalPointIndexStart(vtkm::Id start) { this->GlobalPointIndexStart = start; }
VTKM_EXEC_CONT
vtkm::Id GetPointDimensions() const { return this->PointDimensions; }
VTKM_EXEC_CONT
vtkm::Id GetGlobalPointDimensions() const { return this->GlobalPointDimensions; }
VTKM_EXEC_CONT
vtkm::Id GetCellDimensions() const { return this->PointDimensions - 1; }
VTKM_EXEC_CONT
vtkm::Id GetGlobalCellDimensions() const { return this->GlobalPointDimensions - 1; }
VTKM_EXEC_CONT
SchedulingRangeType GetSchedulingRange(vtkm::TopologyElementTagCell) const
{
@ -138,12 +147,15 @@ public:
void PrintSummary(std::ostream& out) const
{
out << " UniformConnectivity<1> ";
out << "this->PointDimensions[" << this->PointDimensions << "] ";
out << "PointDimensions[" << this->PointDimensions << "] ";
out << "GlobalPointDimensions[" << this->GlobalPointDimensions << "] ";
out << "GlobalPointIndexStart[" << this->GlobalPointIndexStart << "] ";
out << "\n";
}
private:
vtkm::Id PointDimensions = 0;
vtkm::Id GlobalPointDimensions = 0;
vtkm::Id GlobalPointIndexStart = 0;
};
@ -157,15 +169,24 @@ public:
VTKM_EXEC_CONT
void SetPointDimensions(vtkm::Id2 dims) { this->PointDimensions = dims; }
VTKM_EXEC_CONT
void SetGlobalPointDimensions(vtkm::Id2 dims) { this->GlobalPointDimensions = dims; }
VTKM_EXEC_CONT
void SetGlobalPointIndexStart(vtkm::Id2 start) { this->GlobalPointIndexStart = start; }
VTKM_EXEC_CONT
const vtkm::Id2& GetPointDimensions() const { return this->PointDimensions; }
VTKM_EXEC_CONT
const vtkm::Id2& GetGlobalPointDimensions() const { return this->GlobalPointDimensions; }
VTKM_EXEC_CONT
vtkm::Id2 GetCellDimensions() const { return this->PointDimensions - vtkm::Id2(1); }
VTKM_EXEC_CONT
vtkm::Id2 GetGlobalCellDimensions() const { return this->GlobalPointDimensions - vtkm::Id2(1); }
VTKM_EXEC_CONT
vtkm::Id GetNumberOfPoints() const { return vtkm::ReduceProduct(this->GetPointDimensions()); }
@ -303,12 +324,18 @@ public:
void PrintSummary(std::ostream& out) const
{
out << " UniformConnectivity<2> ";
out << "pointDim[" << this->PointDimensions[0] << " " << this->PointDimensions[1] << "] ";
out << "PointDimensions[" << this->PointDimensions[0] << " " << this->PointDimensions[1]
<< "] ";
out << "GlobalPointDimensions[" << this->GlobalPointDimensions[0] << " "
<< this->GlobalPointDimensions[1] << "] ";
out << "GlobalPointIndexStart[" << this->GlobalPointIndexStart[0] << " "
<< this->GlobalPointIndexStart[1] << "] ";
out << std::endl;
}
private:
vtkm::Id2 PointDimensions = { 0, 0 };
vtkm::Id2 GlobalPointDimensions = { 0, 0 };
vtkm::Id2 GlobalPointIndexStart = { 0, 0 };
};
@ -327,15 +354,28 @@ public:
this->CellDim01 = (dims[0] - 1) * (dims[1] - 1);
}
VTKM_EXEC_CONT
void SetGlobalPointDimensions(vtkm::Id3 dims)
{
this->GlobalPointDimensions = dims;
this->GlobalCellDimensions = dims - vtkm::Id3(1);
}
VTKM_EXEC_CONT
void SetGlobalPointIndexStart(vtkm::Id3 start) { this->GlobalPointIndexStart = start; }
VTKM_EXEC_CONT
const vtkm::Id3& GetPointDimensions() const { return this->PointDimensions; }
VTKM_EXEC_CONT
const vtkm::Id3& GetGlobalPointDimensions() const { return this->GlobalPointDimensions; }
VTKM_EXEC_CONT
const vtkm::Id3& GetCellDimensions() const { return this->CellDimensions; }
VTKM_EXEC_CONT
const vtkm::Id3& GetGlobalCellDimensions() const { return this->GlobalCellDimensions; }
VTKM_EXEC_CONT
vtkm::Id GetNumberOfPoints() const { return vtkm::ReduceProduct(this->PointDimensions); }
@ -466,8 +506,12 @@ public:
void PrintSummary(std::ostream& out) const
{
out << " UniformConnectivity<3> ";
out << "pointDim[" << this->PointDimensions[0] << " " << this->PointDimensions[1] << " "
out << "PointDimensions[" << this->PointDimensions[0] << " " << this->PointDimensions[1] << " "
<< this->PointDimensions[2] << "] ";
out << "GlobalPointDimensions[" << this->GlobalPointDimensions[0] << " "
<< this->GlobalPointDimensions[1] << " " << this->GlobalPointDimensions[2] << "] ";
out << "GlobalPointIndexStart[" << this->GlobalPointIndexStart[0] << " "
<< this->GlobalPointIndexStart[1] << " " << this->GlobalPointIndexStart[2] << "] ";
out << std::endl;
}
@ -509,6 +553,8 @@ public:
private:
vtkm::Id3 PointDimensions = { 0, 0, 0 };
vtkm::Id3 GlobalPointDimensions = { 0, 0, 0 };
vtkm::Id3 GlobalCellDimensions = { 0, 0, 0 };
vtkm::Id3 GlobalPointIndexStart = { 0, 0, 0 };
vtkm::Id3 CellDimensions = { 0, 0, 0 };
vtkm::Id CellDim01 = 0;

@ -55,7 +55,6 @@
#include <vtkm/cont/testing/MakeTestDataSet.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/filter/scalar_topology/internal/SpatialDecomposition.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/DataSetMesh.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/filter/scalar_topology/worklet/contourtree_augmented/meshtypes/ContourTreeMesh.h>
@ -154,7 +153,6 @@ void TestHierarchicalHyperSweeper()
"misc/8x9test_HierarchicalAugmentedTree_Block2.dat",
"misc/8x9test_HierarchicalAugmentedTree_Block3.dat" };
vtkm::Id3 globalSize{ 9, 8, 1 };
vtkm::Id3 blocksPerDim{ 2, 2, 1 };
vtkm::Id3 sizes[numBlocks] = { { 5, 4, 1 }, { 5, 5, 1 }, { 5, 4, 1 }, { 5, 5, 1 } };
vtkm::Id3 origins[numBlocks] = { { 0, 0, 0 }, { 0, 3, 0 }, { 4, 0, 0 }, { 4, 3, 0 } };
vtkm::Id3 blockIndices[numBlocks] = { { 0, 0, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 1, 1, 0 } };
@ -174,14 +172,6 @@ void TestHierarchicalHyperSweeper()
vtkm::cont::make_ArrayHandle<vtkm::Id>({ 6, 9, 18, 24, 46, 72, 2 })
};
// Create spatial decomposition
vtkm::filter::scalar_topology::internal::SpatialDecomposition spatialDecomp(
blocksPerDim,
globalSize,
vtkm::cont::make_ArrayHandle(blockIndices, numBlocks, vtkm::CopyFlag::Off),
vtkm::cont::make_ArrayHandle(origins, numBlocks, vtkm::CopyFlag::Off),
vtkm::cont::make_ArrayHandle(sizes, numBlocks, vtkm::CopyFlag::Off));
// Load trees
vtkm::worklet::contourtree_distributed::HierarchicalContourTree<vtkm::FloatDefault>
hct[numBlocks];
@ -209,22 +199,21 @@ void TestHierarchicalHyperSweeper()
RegularDecomposer::CoordinateVector ghosts(3, 1);
RegularDecomposer::DivisionsVector diyDivisions{ 2, 2, 1 }; // HARDCODED FOR TEST
int numDims = static_cast<int>(globalSize[2] > 1 ? 3 : 2);
RegularDecomposer decomposer(numDims,
spatialDecomp.GetVTKmDIYBounds(),
static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()),
shareFace,
wrap,
ghosts,
diyDivisions);
int numDims = 2;
vtkmdiy::DiscreteBounds diyBounds(2);
diyBounds.min[0] = diyBounds.min[1] = 0;
diyBounds.max[0] = static_cast<int>(globalSize[0]);
diyBounds.max[1] = static_cast<int>(globalSize[1]);
RegularDecomposer decomposer(
numDims, diyBounds, numBlocks, shareFace, wrap, ghosts, diyDivisions);
// ... coordinates of local blocks
auto localBlockIndicesPortal = spatialDecomp.LocalBlockIndices.ReadPortal();
std::vector<int> vtkmdiyLocalBlockGids(numBlocks);
for (vtkm::Id bi = 0; bi < numBlocks; bi++)
{
RegularDecomposer::DivisionsVector diyCoords(static_cast<size_t>(numDims));
auto currentCoords = localBlockIndicesPortal.Get(bi);
auto currentCoords = blockIndices[bi];
for (vtkm::IdComponent d = 0; d < numDims; ++d)
{
diyCoords[d] = static_cast<int>(currentCoords[d]);
@ -234,8 +223,7 @@ void TestHierarchicalHyperSweeper()
}
// Define which blocks live on which rank so that vtkmdiy can manage them
vtkmdiy::DynamicAssigner assigner(
comm, comm.size(), static_cast<int>(spatialDecomp.GetGlobalNumberOfBlocks()));
vtkmdiy::DynamicAssigner assigner(comm, comm.size(), numBlocks);
for (vtkm::Id bi = 0; bi < numBlocks; bi++)
{
assigner.set_rank(static_cast<int>(rank),