Port/implement HierarchicalHyperSweeper

This commit is contained in:
Oliver Ruebel 2021-03-03 14:59:58 -08:00 committed by Gunther H. Weber
parent 7506068236
commit a69f83f3a5
13 changed files with 1997 additions and 1 deletions

@ -74,6 +74,9 @@
#include <vtkm/worklet/contourtree_distributed/SpatialDecomposition.h>
#include <vtkm/worklet/contourtree_distributed/TreeGrafter.h>
#include <vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h>
// DIY includes
// clang-format off
VTKM_THIRDPARTY_PRE_INCLUDE

@ -15,6 +15,7 @@ set(headers
ContourTreeBlockData.h
DistributedContourTreeBlockData.h
HierarchicalContourTree.h
HierarchicalHyperSweeper.h
InteriorForest.h
MergeBlockFunctor.h
MultiBlockContourTreeHelper.h
@ -29,3 +30,4 @@ vtkm_declare_headers(${headers})
add_subdirectory(boundary_tree_maker)
add_subdirectory(tree_grafter)
add_subdirectory(hierarchical_contour_tree)
add_subdirectory(hierarchical_hyper_sweeper)

@ -0,0 +1,712 @@
//============================================================================
// 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.
//
//=======================================================================================
//
// Parallel Peak Pruning v. 2.0
//
// Started June 15, 2017
//
// Copyright Hamish Carr, University of Leeds
//
// HierarchicalHyperSweeper.h
//
//=======================================================================================
//
// COMMENTS:
//
// This class encapsulates a hypersweep over the hierarchical contour tree. It is a
// separate class primarily to keep the post-processing separate from the main tree
// construction, but it should also make it easier to generalise to arbitrary computations
//
// Basically, the way that this operates is:
// 1. First, we do a local (standard) hypersweep over the hierarchical tree
// 2. We then fan-in one round at a time. In each round,
// a. We trade the prefix of the array with our logical partner, then
// b. Combine the array prefix with our own
//
// Tactically, when we do MPI, we can either embed it in this unit, or leave it in the
// calling unit. For ease of porting, we will leave all MPI in the calling unit, so
// this unit only needs to do the combination.
//
// Note that we could define an operator to be passed in, and probably want to template it
// that way in the future, but for now, we'll do the first version directly with addition
//
// By assumption, we need a commutative property, since we do not guarantee that we have
// strict ordering along superarcs (which would require sharing a supernode sort with our
// partner, if not globally)
//
//=======================================================================================
#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_h
#include <iomanip>
#include <string>
#include <vtkm/worklet/contourtree_augmented/PrintVectors.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
#include <vtkm/worklet/contourtree_augmented/data_set_mesh/IdRelabeler.h>
#include <vtkm/worklet/contourtree_distributed/HierarchicalContourTree.h>
#include <vtkm/worklet/contourtree_distributed/PrintGraph.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcDependentWeightsWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcTransferWeightsWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountComputeSuperparentIdsWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountInitalizeCountsWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountSubtractLowEndWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferTargetComperator.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateLHEWorklet.h>
#include <vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateRHEWorklet.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
// the class itself
template <typename MeshType, typename FieldType>
class HierarchicalHyperSweeper
{ // class HierarchicalHyperSweeper
public:
// the tree that it hypersweeps over
const HierarchicalContourTree<FieldType>& HierarchicalTree;
// the underlying mesh base block type
const MeshType& BaseBlock;
// the Id of the base block (used for debug output)
vtkm::Id BlockId;
// array of values being operated over (same size as supernode set)
const vtkm::cont::ArrayHandle<FieldType>& SweepValues;
// these are working arrays, lifted up here for ease of debug code
// Subranges of these arrays will be reused in the rounds / iterations rather than being reallocated
// an array for temporary storage of the prefix sums
vtkm::cont::ArrayHandle<FieldType> ValuePrefixSum;
// two arrays for collecting targets of transfers
vtkm::worklet::contourtree_augmented::IdArrayType TransferTarget;
vtkm::worklet::contourtree_augmented::IdArrayType SortedTransferTarget;
// an array for indirect sorting of sets of superarcs
vtkm::worklet::contourtree_augmented::IdArrayType SuperSortPermute;
/// Constructor
/// @param[in] blockId The Id of the base block (used for debug output)
/// @param[in] hierarchicalTree the tree that to hypersweeps over
/// @param[in] baseBlock the underlying mesh base block type
/// @param[in] sweepValues array of values being operated over (same size as supernode set)
HierarchicalHyperSweeper<MeshType, FieldType>(
vtkm::Id blockId,
const HierarchicalContourTree<FieldType>& hierarchicalTree,
const MeshType& baseBlock,
const vtkm::cont::ArrayHandle<FieldType>& sweepValues);
/// Our routines to initialize the sweep need to be static (or externa)l if we are going to use the constructor
/// to run the actual hypersweep
/// @param[in] hierarchicalTree the tree that to hypersweeps over
/// @param[in] baseBlock the underlying mesh base block to initialize from
/// @param[in] localToGlobalIdRelabeler Id relabeler used to compute global indices from local mesh indices
/// @param[out] superarcRegularCounts arrray for the output superarc regular counts
static void InitializeRegularVertexCount(
const HierarchicalContourTree<FieldType>& hierarchicalTree,
const MeshType& baseBlock,
const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler* localToGlobalIdRelabeler,
vtkm::worklet::contourtree_augmented::IdArrayType& superarcRegularCounts);
/// routine to do the local hypersweep using addition / subtraction
/// The funtion use the ComputeSuperarcDependentWeights, ComputeSuperarcTransferWeights,
/// and TransferWeights functions to carry out the local hyper sweep
void LocalHyperSweep();
/// Debug routine to print contents of the HiearchicalHyperSweep
/// @param[in] message Message to print along the debug output
/// @param[in] fileName Name of the file the message is printed from. Usually set to __FILE__
/// @param[in] lineNum Line number in the file where the message is printed from. Usually set to __LINE__
std::string DebugPrint(std::string message, const char* fileName, long lineNum) const;
/// Routine to save the HierarchicalContourTree of this HierarchicalHyperSweeper to a Dot file
/// @param[in] message Message included in the file
/// @param[in] outFileName The name of the file to write the
void SaveHierarchicalContourTreeDot(std::string message, const char* outFileName) const;
protected:
// Functions used internally be LocalHyperSweep to compute the local hyper sweep
/// Routine to compute the correct weights dependent on each superarc in a subrange (defined by the round & iteration)
void ComputeSuperarcDependentWeights(vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode);
/// routine to compute the weights to transfer to superarcs (defined by the round & iteration)
void ComputeSuperarcTransferWeights(vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode);
/// routine to transfer the weights
void TransferWeights(vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode);
private:
/// Used internally to Invoke worklets
vtkm::cont::Invoker Invoke;
}; // class HierarchicalHyperSweeper
template <typename MeshType, typename FieldType>
HierarchicalHyperSweeper<MeshType, FieldType>::HierarchicalHyperSweeper(
vtkm::Id blockId,
const HierarchicalContourTree<FieldType>& hierarchicalTree,
const MeshType& baseBlock,
const vtkm::cont::ArrayHandle<FieldType>& sweepValues)
: HierarchicalTree(hierarchicalTree)
, BaseBlock(baseBlock)
, BlockId(blockId)
, SweepValues(sweepValues)
{ // constructor
// Initalize arrays with 0s
vtkm::cont::ArrayHandleConstant<vtkm::Id> tempZeroArray(
0, this->HierarchicalTree.Supernodes.GetNumberOfValues());
vtkm::cont::Algorithm::Copy(tempZeroArray, this->ValuePrefixSum);
vtkm::cont::Algorithm::Copy(tempZeroArray, this->TransferTarget);
vtkm::cont::Algorithm::Copy(tempZeroArray, this->SortedTransferTarget);
// initialise the supersortPermute to the identity
vtkm::cont::ArrayHandleIndex tempIndexArray(
this->HierarchicalTree.Supernodes.GetNumberOfValues());
vtkm::cont::Algorithm::Copy(tempIndexArray, this->SuperSortPermute);
} // constructor
// static function used to compute the initial superarc regular counts
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::InitializeRegularVertexCount(
const HierarchicalContourTree<FieldType>& hierarchicalTree,
const MeshType& baseBlock,
const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler* localToGlobalIdRelabeler,
vtkm::worklet::contourtree_augmented::IdArrayType& superarcRegularCounts)
{ // InitializeRegularVertexCount()
// TODO: Implement this function
vtkm::cont::Invoker
localInvoke; // Needed because this a static function so we can't use the invoke from the object
// I. Call the mesh to get a list of all regular vertices belonging to the block by global Id
vtkm::worklet::contourtree_augmented::IdArrayType globalIds;
baseBlock.GetOwnedVerticesByGlobalId(localToGlobalIdRelabeler, globalIds);
#ifdef DEBUG_PRINT
{
std::stringstream debugStream;
debugStream << std::endl << "Owned Regular Vertex List";
vtkm::worklet::contourtree_augmented::PrintHeader(globalIds.GetNumberOfValues(), debugStream);
vtkm::worklet::contourtree_augmented::PrintIndices("GlobalId", globalIds, debugStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
}
#endif
// II. Look up the global Ids in the hierarchical tree & convert to superparent Ids
vtkm::worklet::contourtree_augmented::IdArrayType superparents;
{ // scope to make sure temporary variables are deleted
auto findRegularByGlobal = hierarchicalTree.GetFindRegularByGlobal();
auto computeSuperparentIdsWorklet = vtkm::worklet::contourtree_distributed::
hierarchical_hyper_sweeper::InitializeRegularVertexCountComputeSuperparentIdsWorklet();
localInvoke(computeSuperparentIdsWorklet, // worklet to run
globalIds, // input
findRegularByGlobal, // input
hierarchicalTree.Regular2Supernode, // input
hierarchicalTree.Superparents, // input
superparents // output
);
}
#ifdef DEBUG_PRINT
{
std::stringstream debugStream;
vtkm::worklet::contourtree_augmented::PrintIndices("Superparents", superparents, debugStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
}
#endif
// III. Sort the superparent Ids & count the copies of each
vtkm::cont::Algorithm ::Sort(superparents);
#ifdef DEBUG_PRINT
{
std::stringstream debugStream;
vtkm::worklet::contourtree_augmented::PrintIndices("Sorted SP", superparents, debugStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
}
#endif
// initialize the counts to zero.
vtkm::cont::Algorithm::Copy(
vtkm::cont::ArrayHandleConstant<vtkm::Id>(static_cast<vtkm::Id>(0),
hierarchicalTree.Supernodes.GetNumberOfValues()),
superarcRegularCounts);
{ // scope to make sure temporary variables are deleted
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
InitializeRegularVertexCountInitalizeCountsWorklet initalizeCountsWorklet;
// set the count to the Id one off the high end of each range
localInvoke(initalizeCountsWorklet, // worklet
superparents, // input domain
superarcRegularCounts // output
);
}
// now repeat to subtract out the low end
{
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
InitializeRegularVertexCountSubtractLowEndWorklet subtractLowEndWorklet;
localInvoke(subtractLowEndWorklet, // worklet
superparents, // input domain
superarcRegularCounts // output
);
}
// and that is that
#ifdef DEBUG_PRINT
{
std::stringstream debugStream;
vtkm::worklet::contourtree_augmented::PrintIndices(
"SuperarcRegularCounts", superarcRegularCounts, debugStream);
VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
}
#endif
} // InitializeRegularVertexCount()
// routine to do the local hypersweep using addition / subtraction
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::LocalHyperSweep()
{ // LocalHyperSweep()
// TODO: Implement this function
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Starting Local HyperSweep"),
__FILE__,
__LINE__));
#endif
// I. Iterate over all rounds of the hyperstructure
for (vtkm::Id round = 0; round <= this->hierarchicalTree.NumRounds; round++)
{ // per round
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 0 Starting Round"),
__FILE__,
__LINE__));
#endif
// A. Iterate over all iterations of the round
for (vtkm::Id iteration = 0; iteration < this->HierarchicalTree.NumIterations[round];
iteration++)
{ // per iteration
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 1 Iteration ") + std::to_string(iteration) +
std::string(" Step A Starting Iteration"),
__FILE__,
__LINE__));
#endif
// 1. Establish the range of supernode Ids that we want to process
vtkm::Id firstSupernode = this->HierarchicalTree.FirstSupernodePerIteration[round][iteration];
vtkm::Id lastSupernode =
this->HierarchicalTree.FirstSupernodePerIteration[round][iteration + 1];
// call the routine that computes the dependent weights for each superarc in that range
this->ComputeSuperarcDependentWeights(round, iteration, firstSupernode, lastSupernode);
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 1 Iteration ") + std::to_string(iteration) +
std::string(" Step B Dependent Weights Computed"),
__FILE__,
__LINE__));
#endif
// now call the routine that computes the weights to be transferred and the superarcs to which they transfer
this->ComputeSuperarcTransferWeights(round, iteration, firstSupernode, lastSupernode);
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 1 Iteration ") + std::to_string(iteration) +
std::string(" Step C Transfer Weights Computed"),
__FILE__,
__LINE__));
#endif
// transfer the weights
this->TransferWeights(round, iteration, firstSupernode, lastSupernode);
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 1 Iteration ") + std::to_string(iteration) +
std::string(" Step D Weights Transferred"),
__FILE__,
__LINE__));
#endif
} // per iteration
#ifdef DEBUG_PRINT
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
DebugPrint(std::string("Hypersweep Block ") + std::to_string(blockId) +
std::string(" Round ") + std::to_string(round) +
std::string(" Step 2 Ending Round"),
__FILE__,
__LINE__));
#endif
} // per round
} // LocalHyperSweep()
// routine to compute the correct weights dependent on each superarc in a subrange (defined by the round & iteration)
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::ComputeSuperarcDependentWeights(
vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode)
{ // ComputeSuperarcDependentWeights()
(void)
iteration; // avoid compiler warning for unused parmeter. Kept parameter in case we need it for debugging.
// 2. Use sorted prefix sum to compute the total weight to contribute to the super/hypertarget
// Same as std::partial_sum(sweepValues.begin() + firstSupernode, sweepValues.begin() + lastSupernode, valuePrefixSum.begin() + firstSupernode);
{
vtkm::Id numValuesToCopy = lastSupernode - firstSupernode;
// SweepValues[firstSuperNode, lastSupernode)
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType> sweepValuesView(
this->SweepValues, // subset SweepValues
firstSupernode, // start at firstSupernode
numValuesToCopy); // until lastSuperNode (not inclued)
// Target array
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
valuePrefixSumView(this->ValuePrefixSum, // subset SweepValues
firstSupernode, // start at firstSupernode
numValuesToCopy); // until lastSuperNode (not inclued)
// Compute the partial sum for SweepValues[firstSuperNode, lastSupernode) and write to ValuePrefixSum[firstSuperNode, lastSupernode)
vtkm::cont::Algorithm::ScanInclusive(sweepValuesView, // input
valuePrefixSumView); // result of partial sum
}
// Since the prefix sum is over *all* supernodes in the iteration, we need to break it into segments
// There are two cases we have to worry about:
// a. Hyperarcs made up of multiple supernodes
// b. Attachment points (which don't have a corresponding hyperarc)
// and they can be mixed in any given iteration
// Since we have the prefix sum in a separate array, we avoid read/write conflicts
// 3. Compute the segmented weights from the prefix sum array
{
// Create views of the subranges of the arrays we need to update
vtkm::Id numValuesToProcess = lastSupernode - firstSupernode;
vtkm::cont::ArrayHandleCounting<vtkm::Id> supernodeIndex(
firstSupernode, static_cast<vtkm::Id>(1), numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
hierarchicalTreeSuperarcsView(
this->HierarchicalTree.Superarcs, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
hierarchicalTreeHyperparentsView(
this->HierarchicalTree.Hyperparents, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
hierarchicalTreeHypernodesView(
this->HierarchicalTree.Hypernodes, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType> sweepValuesView(
this->SweepValues, firstSupernode, numValuesToProcess);
// create the worklet
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
ComputeSuperarcDependentWeightsWorklet<FieldType>
computeSuperarcDependentWeightsWorklet(
firstSupernode, round, this->HierarchicalTree.NumRounds);
// Execute the worklet
this->Invoke(
computeSuperarcDependentWeightsWorklet, // the worklet
supernodeIndex, // input counting index [firstSupernode, lastSupernode)
hierarchicalTreeSuperarcsView, // input view of hierarchicalTree.Superarcs[firstSupernode, lastSupernode)
hierarchicalTreeHyperparentsView, // input view of hierarchicalTree.Hyperparents[firstSupernode, lastSupernode)
this->hierarchicalTree.Hypernodes, // input full hierarchicalTree.Hypernodes array
this->ValuePrefixSum, // input full ValuePrefixSum array
sweepValuesView // output view of sweepValues[firstSu
);
}
} // ComputeSuperarcDependentWeights()
// routine to compute the weights to transfer to superarcs (defined by the round & iteration)
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::ComputeSuperarcTransferWeights(
vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode)
{ // ComputeSuperarcTransferWeights()
(void)
iteration; // avoid compiler warning for unused parmeter. Kept parameter in case we need it for debugging.
// At this stage, we would otherwise transfer weights by hyperarc, but attachment points don't *have* hyperarcs
// so we will do a transfer by superarc instead, making sure that we only transfer from the last superarc in each
// hyperarc, plus for any attachment point
// 4. Set the amount each superarc wants to transfer, reusing the valuePrefixSum array for the purpose
// and the transfer target
{ // scope ComputeSuperarcTransferWeightsWorklet to make sure temp variables are cleared
// Create ArrayHandleViews of the subrange of values that we need to update
vtkm::Id numValuesToProcess = lastSupernode - firstSupernode;
vtkm::cont::ArrayHandleCounting<vtkm::Id> supernodeIndex(
firstSupernode, static_cast<vtkm::Id>(1), numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
hierarchicalTreeSupernodesView(
this->HierarchicalTree.Supernodes, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
hierarchicalTreeSuperarcsView(
this->HierarchicalTree.Superarcs, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
transferTargetView(this->transferTarget, firstSupernode, numValuesToProcess);
// instantiate the worklet
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
ComputeSuperarcTransferWeightsWorklet computeSuperarcTransferWeightsWorklet(
round, this->HierarchicalTree.NumRounds, lastSupernode);
// call the worklet
this->Invoke(
computeSuperarcTransferWeightsWorklet, // worklet
supernodeIndex, // input counting array [firstSupernode, lastSupernode)
hierarchicalTreeSupernodesView, // input view of hierarchicalTree.supernodes[firstSupernode, lastSupernode)
this->HierarchicalTree.Superparents, // input whole array of hierarchicalTree.superparents
this->HierarchicalTree.Hyperparents, // input whole array of hierarchicalTree.hyperparents
hierarchicalTreeSuperarcsView, // input/output view of hierarchicalTree.superarcs[firstSupernode, lastSupernode)
transferTargetView // input view of transferTarget[firstSupernode, lastSupernode)
);
} // scope ComputeSuperarcTransferWeightsWorklet
// 5. Now we need to sort the transfer targets into contiguous segments
{
// create view of superSortPermute[firstSupernode, lastSupernode) for sorting
vtkm::Id numValuesToProcess = lastSupernode - firstSupernode;
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
superSortPermuteView(this->SuperSortPermute, firstSupernode, numValuesToProcess);
// create comperator for the sort
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::TransferTargetComperator
transferTargetComperator(this->transferTarget);
// sort the subrange of our array
vtkm::cont::Algorithm::Sort(superSortPermuteView, transferTargetComperator);
}
// 6. The [first,last] subrange is now permuted, so we can copy the transfer targets and weights into arrays
// The following code block implements the following for loop using fancy array handles and copy
// for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
// {
// sortedTransferTarget[supernode] = transferTarget[superSortPermute[supernode]];
// valuePrefixSum[supernode] = sweepValues[superSortPermute[supernode]];
// }
{
// copy transfer target in the sorted order
vtkm::Id numValuesToProcess = lastSupernode - firstSupernode;
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
sortedTransferTargetView(this->SortedTransferTarget, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
superSortPermuteView(this->SuperSortPermute, firstSupernode, numValuesToProcess);
auto permutedTransferTarget =
vtkm::cont::make_ArrayHandlePermutation(superSortPermuteView, // idArray
this->TransferTarget); // valueArray
vtkm::cont::Algorithm::Copy(permutedTransferTarget, sortedTransferTargetView);
// Note that any values associated with NO_SUCH_ELEMENT will be ignored
// copy transfer weight in the sorted order
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
valuePrefixSumView(this->ValuePrefixSum, firstSupernode, numValuesToProcess);
auto permutedSweepValues =
vtkm::cont::make_ArrayHandlePermutation(superSortPermuteView, // idArray
this->SweepValues); // valueArray
vtkm::cont::Algorithm::Copy(permutedSweepValues, valuePrefixSumView);
}
} // ComputeSuperarcTransferWeights()
// routine to transfer the weights
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::TransferWeights(vtkm::Id round,
vtkm::Id iteration,
vtkm::Id firstSupernode,
vtkm::Id lastSupernode)
{ // TransferWeights()
// avoid compiler warning for unused parmeters. Kept parameters in case we need it for debugging.
(void)round;
(void)iteration;
// 7. Now perform a segmented prefix sum
// Same as std::partial_sum(valuePrefixSum.begin() + firstSupernode, valuePrefixSum.begin() + lastSupernode, valuePrefixSum.begin() + firstSupernode);
{
vtkm::Id numValuesToCopy = lastSupernode - firstSupernode;
// ValuePrefixSum[firstSuperNode, lastSupernode)
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
valuePrefixSumView(this->ValuePrefixSum, // subset ValuePrefixSum
firstSupernode, // start at firstSupernode
numValuesToCopy); // until lastSuperNode (not inclued)
// TODO: If it is safe to use the same array as input and output for ScanInclusive then this code should be updated to avoid the extra copy
// In this case our traget array is the same as our source array. For safety we
// store the values of our prefix sum in a temporary arrya and then copy the values
// back into our valuePrefixSumView at the end
vtkm::cont::ArrayHandle<FieldType> tempScanInclusiveTarget;
tempScanInclusiveTarget.Allocate(numValuesToCopy);
// Compute the partial sum for SweepValues[firstSuperNode, lastSupernode) and write to ValuePrefixSum[firstSuperNode, lastSupernode)
vtkm::cont::Algorithm::ScanInclusive(valuePrefixSumView, // input
tempScanInclusiveTarget); // result of partial sum
// Now copy the values from our prefix sum back
vtkm::cont::Algorithm::Copy(tempScanInclusiveTarget, valuePrefixSumView);
}
// 7a. and 7b.
{
// Prepare the approbriate array views for our worklet. This is done to allow us to
// use FieldIn instead of having to transfer the entire array to the device when we
// really only need a subrange
vtkm::Id numValuesToProcess = lastSupernode - firstSupernode;
vtkm::cont::ArrayHandleCounting<vtkm::Id> supernodeIndex(
firstSupernode, static_cast<vtkm::Id>(1), numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
sortedTransferTargetView(this->SortedTransferTarget, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
sortedTransferTargetShiftedView(
this->SortedTransferTarget, firstSupernode + 1, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
valuePrefixSumView(this->ValuePrefixSum, firstSupernode, numValuesToProcess);
vtkm::cont::ArrayHandleView<vtkm::worklet::contourtree_augmented::IdArrayType>
valuePrefixSumShiftedView(this->ValuePrefixSum, firstSupernode - 1, numValuesToProcess);
auto sweepValuePermuted =
vtkm::cont::make_ArrayHandlePermutation(sortedTransferTargetView, // idArray
this->SweepValues); // valueArray
// 7a. Find the RHE of each group and transfer the prefix sum weight
// Note that we do not compute the transfer weight separately, we add it in place instead
// Instantiate the worklet
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
TransferWeightsUpdateRHEWorklet transferWeightsUpdateRHEWorklet(lastSupernode);
// Invoke the worklet
this->Invoke(
transferWeightsUpdateRHEWorklet, // worklet
supernodeIndex, // input counting array [firstSupernode, lastSupernode)
sortedTransferTargetView, // input view of sortedTransferTarget[firstSupernode, lastSupernode)
sortedTransferTargetShiftedView, // input view of sortedTransferTarget[firstSupernode+1, lastSupernode+1)
valuePrefixSumView, // input view of valuePrefixSum[firstSupernode, lastSupernode)
sweepValuePermuted // output view of sweepValues permuted by sortedTransferTarget[firstSupernode, lastSupernode). Use FieldInOut since we don't overwrite all values.
);
// 7b. Now find the LHE of each group and subtract out the prior weight
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
TransferWeightsUpdateLHEWorklet transferWeightsUpdateLHEWorklet(firstSupernode);
this->Invoke(
transferWeightsUpdateLHEWorklet, // worklet
supernodeIndex, // input counting array [firstSupernode, lastSupernode)
sortedTransferTargetView, // input view of sortedTransferTarget[firstSupernode, lastSupernode)
sortedTransferTargetShiftedView, // input view of sortedTransferTarget[firstSupernode+1, lastSupernode+1)
valuePrefixSumShiftedView, // input view of valuePrefixSum[firstSupernode-1, lastSupernode-1)
sweepValuePermuted // output view of sweepValues permuted by sortedTransferTarget[firstSupernode, lastSupernode). Use FieldInOut since we don't overwrite all values.
);
}
} // TransferWeights()
// debug routine
template <typename MeshType, typename FieldType>
std::string HierarchicalHyperSweeper<MeshType, FieldType>::DebugPrint(std::string message,
const char* fileName,
long lineNum) const
{ // DebugPrint()
std::stringstream resultStream;
resultStream << std::endl;
resultStream << "----------------------------------------" << std::endl;
resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
<< lineNum << std::endl;
resultStream << std::left << message << std::endl;
resultStream << "Hypersweep Value Array Contains: " << std::endl;
resultStream << "----------------------------------------" << std::endl;
resultStream << std::endl;
vtkm::worklet::contourtree_augmented::PrintHeader(this->SweepValues.GetNumberOfValues(),
resultStream);
vtkm::worklet::contourtree_augmented::PrintIndices("Volume", this->SweepValues, -1, resultStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Prefix Sum", this->ValuePrefixSum - 1, resultStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Transfer To", this->TransferTarget - 1, resultStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Sorted Transfer", this->SortedTransferTarget - 1, resultStream);
vtkm::worklet::contourtree_augmented::PrintIndices(
"Sort Permute", this->SuperSortPermute - 1, resultStream);
} // DebugPrint()
// Routine to save the hierarchical tree to file
template <typename MeshType, typename FieldType>
void HierarchicalHyperSweeper<MeshType, FieldType>::SaveHierarchicalContourTreeDot(
std::string message,
const char* outFileName) const
{ // SaveHierarchicalContourTreeDot()
std::string hierarchicalTreeDotString =
HierarchicalContourTreeDotGraphPrint<vtkm::worklet::contourtree_augmented::IdArrayType>(
message,
this->HierarchicalTree,
SHOW_SUPER_STRUCTURE | SHOW_HYPER_STRUCTURE | SHOW_ALL_IDS | SHOW_ALL_SUPERIDS |
SHOW_ALL_HYPERIDS | SHOW_EXTRA_DATA, //|GV_NODE_NAME_USES_GLOBAL_ID
this->BlockId,
this->SweepValues);
std::ofstream hierarchicalTreeFile(outFileName);
hierarchicalTreeFile << hierarchicalTreeDotString;
} // SaveHierarchicalContourTreeDot
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -404,7 +404,10 @@ void TreeGrafter<MeshType, FieldType>::GraftInteriorForests(
this->HierarchicalSuperId, // input
attachmentCounter // output
);
vtkm::Id numAttachmentPoints = vtkm::cont::Algorithm::Reduce(attachmentCounter, 0, vtkm::Sum());
// Compute the sum of all values in attachmentCounter. vtkm::Add() is the default (so it could be omitted).
// We include it here to be more explicit about what Reduce does.
vtkm::Id numAttachmentPoints =
vtkm::cont::Algorithm::Reduce(attachmentCounter, static_cast<vtkm::Id>(0), vtkm::Add());
// if there are any at all, we need an extra iteration
if (numAttachmentPoints > 0)

@ -0,0 +1,22 @@
##============================================================================
## 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.
##============================================================================
set(headers
InitializeRegularVertexCountComputeSuperparentIds.h
InitializeRegularVertexCountInitalizeCountsWorklet.h
InitializeRegularVertexCountSubtractLowEndWorklet.h
ComputeSuperarcDependentWeightsWorklet.h
ComputeSuperarcTransferWeightsWorklet.h
TransferTargetComperator.h
TransferWeightsUpdateRHEWorklet.h
TransferWeightsUpdateLHEWorklet.h
)
vtkm_declare_headers(${headers})

@ -0,0 +1,205 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_compute_superarc_dependent_weights_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_compute_superarc_dependent_weights_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.ComputeSuperarcDependentWeightsWorklet(...) to
/// compute the superarc dependent weights
template <typename FieldType>
class ComputeSuperarcDependentWeightsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn supernodeIndex, // counting index [firstSupernode, lastSupernode)
FieldIn
hierarchicalTreeSuperarcsView, // view of hierarchicalTree.Superarcs[firstSupernode, lastSupernode)
FieldIn
hierarchicalTreeHyperparentsView, // view of hierarchicalTree.Hyperparents[firstSupernode, lastSupernode)
WholeArrayIn hierarchicalTreeHypernodes, // whole hierarchicalTree.Hypernodes array
WholeArrayIn valuePrefixSum, // whole valuePrefixSum array
FieldInOut sweepValuesView // output view of sweepValues[firstSupernode, lastSupernode)
);
using ExecutionSignature = void(InputIndex, _1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeSuperarcDependentWeightsWorklet(const vtkm::Id& firstSupernode,
const vtkm::Id& round,
const vtkm::Id& hierarchicalTreeNumRounds)
: FirstSupernode(firstSupernode)
, Round(round)
, HierarchicalTreeNumRounds(hierarchicalTreeNumRounds)
{
}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(
const vtkm::Id& supernode,
const vtkm::Id& superarcTo, // same as hierarchicalTree.superarcs[supernode];
const vtkm::Id& hyperparent, // same as hierarchicalTree.hyperparents[supernode];
const InFieldPortalType& hierarchicalTreeHypernodesPortal,
const InFieldPortalType& valuePrefixSumPortal,
vtkm::Id& sweepValue) const
{
// per supernode
// if there is no superarc, it is either the root of the tree or an attachment point
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarcTo))
{ // null superarc
// next we test for whether it is the global root
if (this->Round == this->HierarchicalTreeNumRounds)
{ // global root
// this is guaranteed to be the only element in it's iteration
// so the prefix sum is good as it stands
sweepValue = valuePrefixSumPortal.Get(supernode);
} // global root
else
{ // attachment point
// could be the first in the iteration, in which case it is correct
if (supernode == this->FirstSupernode)
{
sweepValue = valuePrefixSumPortal.Get(supernode);
}
// otherwise, we are guaranteed that it's a length one chain, so subtract predecessor
else
{
sweepValue =
valuePrefixSumPortal.Get(supernode) - valuePrefixSumPortal.Get(supernode - 1);
}
} // attachment point
} // null superarc
else
{ // actual superarc
// use the hyperparent to find the hypernode at the beginning of the chain
vtkm::Id hyperparentSuperId = hierarchicalTreeHypernodesPortal.Get(hyperparent);
// now we check to see which value we subtract
FieldType baseValue = 0;
if (hyperparentSuperId != this->FirstSupernode)
{
baseValue = valuePrefixSumPortal.Get(hyperparentSuperId - 1);
}
// for all others, remove the hyperparent's prefix sum to get the "relative" prefix sum
sweepValue = valuePrefixSumPortal.Get(supernode) - baseValue;
} // actual superarc
// In serial this worklet implements the following operation
/*
for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
{ // per supernode
// we need to know the superarc first
vtkm::Id superarcTo = hierarchicalTree.superarcs[supernode];
// if there is no superarc, it is either the root of the tree or an attachment point
if (noSuchElement(superarcTo))
{ // null superarc
// next we test for whether it is the global root
if (round == hierarchicalTree.nRounds)
{ // global root
// this is guaranteed to be the only element in it's iteration
// so the prefix sum is good as it stands
sweepValues[supernode] = valuePrefixSum[supernode];
} // global root
else
{ // attachment point
// could be the first in the iteration, in which case it is correct
if (supernode == firstSupernode)
sweepValues[supernode] = valuePrefixSum[supernode];
// otherwise, we are guaranteed that it's a length one chain, so subtract predecessor
else
sweepValues[supernode] = valuePrefixSum[supernode] - valuePrefixSum[supernode-1];
} // attachment point
} // null superarc
else
{ // actual superarc
// use the hyperparent to find the hypernode at the beginning of the chain
vtkm::Id hyperparent = hierarchicalTree.hyperparents[supernode];
vtkm::Id hyperparentSuperId = hierarchicalTree.hypernodes[hyperparent];
// now we check to see which value we subtract
dataType baseValue = 0;
if (hyperparentSuperId != firstSupernode)
baseValue = valuePrefixSum[hyperparentSuperId - 1];
// for all others, remove the hyperparent's prefix sum to get the "relative" prefix sum
sweepValues[supernode] = valuePrefixSum[supernode] - baseValue;
} // actual superarc
} // per supernode
*/
} // operator()()
private:
const vtkm::Id FirstSupernode;
const vtkm::Id Round;
const vtkm::Id HierarchicalTreeNumRounds;
}; // ComputeSuperarcDependentWeightsWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,196 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_compute_superarc_transfer_weights_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_compute_superarc_transfer_weights_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.InitializeRegularVertexCount(...) to
/// subtract out the low end from the superarc regular counts
class ComputeSuperarcTransferWeightsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn supernodeIndex, // counting array [firstSupernode, lastSupernode)
FieldIn
hierarchicalTreeSupernodesView, // view of hierarchicalTree.supernodes[firstSupernode, lastSupernode)
WholeArrayIn hierarchicalTreeSuperparents, // whole array of hierarchicalTree.superparents
WholeArrayIn hierarchicalTreeHyperparents, // whole array of hierarchicalTree.hyperparents
FieldInOut
hierarchicalTreeSuperarcsView, // view of hierarchicalTree.superarcs[firstSupernode, lastSupernode)
FieldOut transferTargetView // view of transferTarget[firstSupernode, lastSupernode)
);
using ExecutionSignature = void(_1, _2, _3, _4, _5, _6);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
ComputeSuperarcTransferWeightsWorklet(const vtkm::Id& round,
const vtkm::Id& hierarchicalTreeNumRounds,
const vtkm::Id& lastSupernode)
: Round(round)
, HierarchicalTreeNumRounds(hierarchicalTreeNumRounds)
, LastSupernode(lastSupernode)
{
}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(
const vtkm::Id& supernode,
const vtkm::Id& supernodeRegularId, // same as hierarchicalTree.supernodes[supernode];
const InFieldPortalType& hierarchicalTreeSuperparentsPortal,
const InFieldPortalType& hierarchicalTreeHyperparentsPortal,
vtkm::Id& superarcTo, // same as hierarchicalTree.superarcs[supernode];
vtkm::Id& transferTarget // same as transferTarget[supernode]
) const
{
// per supernode
// if there is no superarc, it is either the root of the tree or an attachment point
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superarcTo))
{ // null superarc
// next we test for whether it is the global root
if (this->Round == HierarchicalTreeNumRounds)
{ // global root
// no transfer, so no target
transferTarget = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
} // global root
else
{ // attachment point
// set the transfer target
transferTarget = hierarchicalTreeSuperparentsPortal.Get(supernodeRegularId);
} // attachment point
} // null superarc
else
{ // actual superarc
// test for the last in the subrange / last on the hyperarc
if ((supernode != this->LastSupernode - 1) &&
(hierarchicalTreeHyperparentsPortal.Get(supernode) ==
hierarchicalTreeHyperparentsPortal.Get(supernode + 1)))
{ // not a superarc we care about
transferTarget = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
} // not a superarc we care about
else
{ // a superarc we care about
// strip off the flag bits
superarcTo = vtkm::worklet::contourtree_augmented::MaskedIndex(superarcTo);
// and set the weight & target
transferTarget = superarcTo;
} // a superarc we care about
} // actual superarc
// In serial this worklet implements the following operation
/*
for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
{ // per supernode
// we need to know the superarc
vtkm::Id superarcTo = hierarchicalTree.superarcs[supernode];
vtkm::Id supernodeRegularId = hierarchicalTree.supernodes[supernode];
// if there is no superarc, it is either the root of the tree or an attachment point
if (noSuchElement(superarcTo))
{ // null superarc
// next we test for whether it is the global root
if (round == hierarchicalTree.nRounds)
{ // global root
// no transfer, so no target
transferTarget[supernode] = NO_SUCH_ELEMENT;
} // global root
else
{ // attachment point
// set the transfer target
transferTarget[supernode] = hierarchicalTree.superparents[supernodeRegularId];
} // attachment point
} // null superarc
else
{ // actual superarc
// test for the last in the subrange / last on the hyperarc
if ((supernode != lastSupernode - 1) && (hierarchicalTree.hyperparents[supernode] == hierarchicalTree.hyperparents[supernode+1]))
{ // not a superarc we care about
transferTarget[supernode] = NO_SUCH_ELEMENT;
} // not a superarc we care about
else
{ // a superarc we care about
// strip off the flag bits
superarcTo = maskedIndex(superarcTo);
// and set the weight & target
transferTarget[supernode] = superarcTo;
} // a superarc we care about
} // actual superarc
} // per supernode
*/
} // operator()()
private:
const vtkm::Id Round;
const vtkm::Id HierarchicalTreeNumRounds;
const vtkm::Id LastSupernode;
}; // ComputeSuperarcTransferWeightsWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,160 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_compute_superparent_ids_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_compute_superparent_ids_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.InitializeRegularVertexCount(...) to
/// Look up the global Ids in the hierarchical tree & convert to superparent Ids
class InitializeRegularVertexCountComputeSuperparentIdsWorklet
: public vtkm::worklet::WorkletMapField
{
public:
// TODO: We could avoid the need for WholeArrayIn if we did the findRegularByGlobal mapping outside of the worklet first and then use the mapped
using ControlSignature = void(FieldIn globalIds, // input
ExecObject findRegularByGlobal, // input
WholeArrayIn hierarchicalTreeRegular2Supernode, // input
WholeArrayIn hierarchicalTreeSuperparents, // input
FieldOut superparents // output
);
using ExecutionSignature = void(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
InitializeRegularVertexCountComputeSuperparentIdsWorklet() {}
template <typename ExecObjType, typename InFieldPortalType>
VTKM_EXEC vtkm::Id operator()(const vtkm::Id& globalId,
const ExecObjType& findRegularByGlobal,
const InFieldPortalType& hierarchicalTreeRegular2SupernodePortal,
const InFieldPortalType& hierarchicalTreeSuperparentsPortal,
vtkm::Id& superparent) const
{
// per vertex
// retrieve the regular Id (should ALWAYS exist)
vtkm::Id hierarchicalRegularId = findRegularByGlobal(globalId);
// be paranoid
if (vtkm::worklet::contourtree_augmented::NoSuchElement(hierarchicalRegularId))
{
superparent = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT;
}
else
{
// Attachment points cause a minor problem - they are supernodes, but can have a different
// superparent than themselves (or the same one). We therefore test explicitly whether we
// are a supernode, and use either supernodeId or superparent depending on this test
// retrieve the super Id
vtkm::Id superId = hierarchicalTreeRegular2SupernodePortal.Get(hierarchicalRegularId);
// if it doesn't have one, use it's superparent
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superId))
{
superparent = hierarchicalTreeSuperparentsPortal.Get(hierarchicalRegularId);
}
else
{
// if it does have a superId, use it
superparent = superId;
}
}
// In serial this worklet implements the following operation
/*
for (vtkm::Id vertex = 0; vertex < globalIds.GetNumberOfValues(); vertex++)
{ // per vertex
// retrieve the regular Id (should ALWAYS exist)
vtkm::Id hierarchicalRegularId = hierarchicalTree.FindRegularByGlobal(globalIds[vertex]);
// be paranoid
if (noSuchElement(hierarchicalRegularId))
superparents[vertex] = NO_SUCH_ELEMENT;
else
{ // found a regular Id
// Attachment points cause a minor problem - they are supernodes, but can have a different
// superparent than themselves (or the same one). We therefore test explicitly whether we
// are a supernode, and use either supernodeId or superparent depending on this test
// retrieve the super Id
vtkm::Id superId = hierarchicalTree.regular2supernode[hierarchicalRegularId];
// if it doesn't have one, use it's superparent
if (noSuchElement(superId))
superparents[vertex] = hierarchicalTree.superparents[hierarchicalRegularId];
else
// if it does have a superId, use it
superparents[vertex] = superId;
} // found a regular Id
} // per vertex
*/
} // operator()()
}; // InitializeRegularVertexCountComputeSuperparentIdsWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,138 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_initialize_counts_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_initialize_counts_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.InitializeRegularVertexCount(...) to
/// set the count to the Id one off the high end of each range
class InitializeRegularVertexCountInitalizeCountsWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn superparents, WholeArrayInOut superarcRegularCounts);
using ExecutionSignature = void(InputIndex, _1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
InitializeRegularVertexCountInitalizeCountsWorklet() {}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& vertex,
const InFieldPortalType superparentsPortal,
const InOutFieldPortalType superarcRegularCountsPortal) const
{
// per vertex
// retrieve the superparent
vtkm::Id superparent = superparentsPortal.Get(vertex);
// if it's NSE, ignore (should never happen, but . . . )
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superparent))
{
return;
}
// if its the last element, always write
if (vertex == superparentsPortal.GetNumberOfValues() - 1)
{
superarcRegularCountsPortal.Set(superparent, vertex + 1);
}
// otherwise, only write if different from next one
else
{
if (superparentsPortal.Get(vertex + 1) != superparent)
{
superarcRegularCountsPortal.Set(superparent, vertex + 1);
}
}
// In serial this worklet implements the following operation
/*
for (vtkm::Id vertex = 0; vertex < superparents.size(); vertex++)
{ // per vertex
// retrieve the superparent
vtkm::Id superparent = superparents[vertex];
// if it's NSE, ignore (should never happen, but . . . )
if (noSuchElement(superparent))
continue;
// if its the last element, always write
if (vertex == superparents.size() - 1)
superarcRegularCounts[superparent] = vertex+1;
// otherwise, only write if different from next one
else
if (superparents[vertex+1] != superparent)
superarcRegularCounts[superparent] = vertex+1;
} // per vertex
*/
} // operator()()
}; // InitializeRegularVertexCountInitalizeCountsWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,141 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_subtract_low_end_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_initialize_regular_vertex_count_subtract_low_end_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.InitializeRegularVertexCount(...) to
/// subtract out the low end from the superarc regular counts
class InitializeRegularVertexCountSubtractLowEndWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(WholeArrayIn superparents, WholeArrayInOut superarcRegularCounts);
using ExecutionSignature = void(InputIndex, _1, _2);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
InitializeRegularVertexCountSubtractLowEndWorklet() {}
template <typename InFieldPortalType, typename InOutFieldPortalType>
VTKM_EXEC void operator()(const vtkm::Id& vertex,
const InFieldPortalType superparentsPortal,
const InOutFieldPortalType superarcRegularCountsPortal) const
{
// per vertex
// retrieve the superparent
vtkm::Id superparent = superparentsPortal.Get(vertex);
// if it's NSE, ignore (should never happen, but . . . )
if (vtkm::worklet::contourtree_augmented::NoSuchElement(superparent))
{
return;
}
// if its the first element, always write
if (vertex == 0)
{
superarcRegularCountsPortal.Set(superparent,
superarcRegularCountsPortal.Get(superparent) - vertex);
}
// otherwise, only write if different from previous one
else
{
if (superparentsPortal.Get(vertex - 1) != superparent)
{
superarcRegularCountsPortal.Set(superparent,
superarcRegularCountsPortal.Get(superparent) - vertex);
}
}
// In serial this worklet implements the following operation
/*
for (vtkm::Id vertex = 0; vertex < superparents.GetNumberOfValues(); vertex++)
{ // per vertex
// retrieve the superparent
vtkm::Id superparent = superparents[vertex];
// if it's NSE, ignore (should never happen, but . . . )
if (noSuchElement(superparent))
continue;
// if its the first element, always write
if (vertex == 0)
superarcRegularCounts[superparent] -= vertex;
// otherwise, only write if different from previous one
else
if (superparents[vertex-1] != superparent)
superarcRegularCounts[superparent] -= vertex;
} // per vertex
*/
} // operator()()
}; // InitializeRegularVertexCountSubtractLowEndWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,120 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_target_comperator_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_target_comperator_h
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ExecutionObjectBase.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
// comperator function for an indirect sort on the superarc target
class TransferTargetComperatorImpl
{
public:
using IdArrayPortalType =
typename vtkm::worklet::contourtree_augmented::IdArrayType::ReadPortalType;
// constructor - takes vectors as parameters
VTKM_CONT
TransferTargetComperatorImpl(IdArrayPortalType superarcPortal)
: SuperarcPortal(superarcPortal)
{ // constructor
} // constructor
// () operator - gets called to do comparison
VTKM_EXEC
bool operator()(const vtkm::Id& left, const vtkm::Id& right) const
{ // operator()
return this->SuperarcPortal.Get(left) < this->SuperarcPortal.Get(right);
} // operator()
private:
IdArrayPortalType SuperarcPortal;
}; // TransferTargetComperatorImpl
class TransferTargetComperator : public vtkm::cont::ExecutionObjectBase
{
public:
// constructor - takes vectors as parameters
VTKM_CONT
TransferTargetComperator(const vtkm::worklet::contourtree_augmented::IdArrayType superarcs)
: Superarcs(superarcs)
{ // constructor
} // constructor
VTKM_CONT TransferTargetComperatorImpl PrepareForExecution(vtkm::cont::DeviceAdapterId device,
vtkm::cont::Token& token) const
{
return TransferTargetComperatorImpl(this->Superarcs.PrepareForInput(device, token));
}
private:
vtkm::worklet::contourtree_augmented::IdArrayType Superarcs;
}; // TransferTargetComperator
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,152 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_weights_update_lhe_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_weights_update_lhe_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.TransferWeights(...) to implement
/// step 7b. Now find the LHE of each group and subtract out the prior weight
class TransferWeightsUpdateLHEWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn supernodeIndex, // input counting array [firstSupernode, lastSupernode)
FieldIn
sortedTransferTargetView, // input view of sortedTransferTarget[firstSupernode, lastSupernode)
FieldIn
sortedTransferTargetShiftedView, // input view of sortedTransferTarget[firstSupernode+1, lastSupernode+1)
FieldIn
valuePrefixSumShiftedView, // input view of valuePrefixSum[firstSupernode-1, lastSupernode-1)
FieldInOut
sweepValuePermuted // output view of sweepValues permuted by sortedTransferTarget[firstSupernode, lastSupernode). Use FieldInOut since we don't overwrite all values.
);
using ExecutionSignature = void(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
TransferWeightsUpdateLHEWorklet(const vtkm::Id& firstSupernode)
: FirstSupernode(firstSupernode)
{
}
VTKM_EXEC void operator()(
const vtkm::Id& supernode,
const vtkm::Id& sortedTransferTargetValue, // same as sortedTransferTarget[supernode]
const vtkm::Id& sortedTransferTargetNextValue, // same as sortedTransferTarget[supernode+1]
const vtkm::Id& valuePrefixSumPreviousValue, // same as valuePrefixSum[supernode-1]
vtkm::Id& sweepValue // same as sweepValues[sortedTransferTarget[supernode]]
) const
{
// per supernode
// ignore any that point at NO_SUCH_ELEMENT
if (vtkm::worklet::contourtree_augmented::NoSuchElement(sortedTransferTargetValue))
{
return;
}
// the LHE at 0 is special - it subtracts zero. In practice, since NO_SUCH_ELEMENT will sort low, this will never
// occur, but let's keep the logic strict
if (supernode == this->FirstSupernode)
{ // LHE 0
sweepValue -= 0;
} // LHE 0
else if (sortedTransferTargetValue != sortedTransferTargetNextValue)
{ // LHE not 0
sweepValue -= valuePrefixSumPreviousValue;
} // LHE not 0
// In serial this worklet implements the following operation
/*
for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
{ // per supernode
// ignore any that point at NO_SUCH_ELEMENT
if (noSuchElement(sortedTransferTarget[supernode]))
continue;
// the LHE at 0 is special - it subtracts zero. In practice, since NO_SUCH_ELEMENT will sort low, this will never
// occur, but let's keep the logic strict
if (supernode == firstSupernode)
{ // LHE 0
sweepValues[sortedTransferTarget[supernode]] -= 0;
} // LHE 0
else if (sortedTransferTarget[supernode] != sortedTransferTarget[supernode-1])
{ // LHE not 0
sweepValues[sortedTransferTarget[supernode]] -= valuePrefixSum[supernode-1];
} // LHE not 0
} // per supernode
*/
} // operator()()
private:
const vtkm::Id FirstSupernode;
}; // TransferWeightsUpdateLHEWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif

@ -0,0 +1,142 @@
//============================================================================
// 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_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_weights_update_rhe_worklet_h
#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_transfer_weights_update_rhe_worklet_h
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/contourtree_augmented/Types.h>
namespace vtkm
{
namespace worklet
{
namespace contourtree_distributed
{
namespace hierarchical_hyper_sweeper
{
/// Worklet used in HierarchicalHyperSweeper.TransferWeights(...) to implement
/// step 7a. Find the RHE of each group and transfer the prefix sum weight.
/// Note that we do not compute the transfer weight separately, we add it in place instead
class TransferWeightsUpdateRHEWorklet : public vtkm::worklet::WorkletMapField
{
public:
using ControlSignature = void(
FieldIn supernodeIndex, // input counting array [firstSupernode, lastSupernode)
FieldIn
sortedTransferTargetView, // input view of sortedTransferTarget[firstSupernode, lastSupernode)
FieldIn
sortedTransferTargetShiftedView, // input view of sortedTransferTarget[firstSupernode+1, lastSupernode+1)
FieldIn valuePrefixSumView, // input view of valuePrefixSum[firstSupernode, lastSupernode)
FieldInOut
sweepValuePermuted // output view of sweepValues permuted by sortedTransferTarget[firstSupernode, lastSupernode). Use FieldInOut since we don't overwrite all values.
);
using ExecutionSignature = void(_1, _2, _3, _4, _5);
using InputDomain = _1;
// Default Constructor
VTKM_EXEC_CONT
TransferWeightsUpdateRHEWorklet(const vtkm::Id& lastSupernode)
: LastSupernode(lastSupernode)
{
}
VTKM_EXEC void operator()(
const vtkm::Id& supernode,
const vtkm::Id& sortedTransferTargetValue, // same as sortedTransferTarget[supernode]
const vtkm::Id& sortedTransferTargetNextValue, // same as sortedTransferTarget[supernode+1]
const vtkm::Id& valuePrefixSum, // same as valuePrefixSum[supernode]
vtkm::Id& sweepValue // same as sweepValues[sortedTransferTarget[supernode]]
) const
{
// per supernode
// ignore any that point at NO_SUCH_ELEMENT
if (vtkm::worklet::contourtree_augmented::NoSuchElement(sortedTransferTargetValue))
{
return;
}
// the RHE of each segment transfers its weight (including all irrelevant prefixes)
if ((supernode == this->LastSupernode - 1) ||
(sortedTransferTargetValue != sortedTransferTargetNextValue))
{ // RHE of segment
sweepValue += valuePrefixSum;
} // RHE of segment
// In serial this worklet implements the following operation
/*
for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
{ // per supernode
// ignore any that point at NO_SUCH_ELEMENT
if (noSuchElement(sortedTransferTarget[supernode]))
continue;
// the RHE of each segment transfers its weight (including all irrelevant prefixes)
if ((supernode == lastSupernode - 1) || (sortedTransferTarget[supernode] != sortedTransferTarget[supernode+1]))
{ // RHE of segment
sweepValues[sortedTransferTarget[supernode]] += valuePrefixSum[supernode];
} // RHE of segment
} // per supernode
*/
} // operator()()
private:
const vtkm::Id LastSupernode;
}; // TransferWeightsUpdateRHEWorklet
} // namespace hierarchical_hyper_sweeper
} // namespace contourtree_distributed
} // namespace worklet
} // namespace vtkm
#endif