From a69f83f3a5e8ad41ced6ecca5f0369960d22ea96 Mon Sep 17 00:00:00 2001 From: Oliver Ruebel Date: Wed, 3 Mar 2021 14:59:58 -0800 Subject: [PATCH] Port/implement HierarchicalHyperSweeper --- vtkm/filter/ContourTreeUniformDistributed.hxx | 3 + .../contourtree_distributed/CMakeLists.txt | 2 + .../HierarchicalHyperSweeper.h | 712 ++++++++++++++++++ .../contourtree_distributed/TreeGrafter.h | 5 +- .../hierarchical_hyper_sweeper/CMakeLists.txt | 22 + .../ComputeSuperarcDependentWeightsWorklet.h | 205 +++++ .../ComputeSuperarcTransferWeightsWorklet.h | 196 +++++ ...rVertexCountComputeSuperparentIdsWorklet.h | 160 ++++ ...RegularVertexCountInitalizeCountsWorklet.h | 138 ++++ ...eRegularVertexCountSubtractLowEndWorklet.h | 141 ++++ .../TransferTargetComperator.h | 120 +++ .../TransferWeightsUpdateLHEWorklet.h | 152 ++++ .../TransferWeightsUpdateRHEWorklet.h | 142 ++++ 13 files changed, 1997 insertions(+), 1 deletion(-) create mode 100644 vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/CMakeLists.txt create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcDependentWeightsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcTransferWeightsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountComputeSuperparentIdsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountInitalizeCountsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountSubtractLowEndWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferTargetComperator.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateLHEWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateRHEWorklet.h diff --git a/vtkm/filter/ContourTreeUniformDistributed.hxx b/vtkm/filter/ContourTreeUniformDistributed.hxx index e95cc20a7..bb1f38f4b 100644 --- a/vtkm/filter/ContourTreeUniformDistributed.hxx +++ b/vtkm/filter/ContourTreeUniformDistributed.hxx @@ -74,6 +74,9 @@ #include #include + +#include + // DIY includes // clang-format off VTKM_THIRDPARTY_PRE_INCLUDE diff --git a/vtkm/worklet/contourtree_distributed/CMakeLists.txt b/vtkm/worklet/contourtree_distributed/CMakeLists.txt index 9f08404e6..26a5b56e1 100644 --- a/vtkm/worklet/contourtree_distributed/CMakeLists.txt +++ b/vtkm/worklet/contourtree_distributed/CMakeLists.txt @@ -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) diff --git a/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h b/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h new file mode 100644 index 000000000..902546cc8 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ + +// the class itself +template +class HierarchicalHyperSweeper +{ // class HierarchicalHyperSweeper +public: + // the tree that it hypersweeps over + const HierarchicalContourTree& 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& 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 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( + vtkm::Id blockId, + const HierarchicalContourTree& hierarchicalTree, + const MeshType& baseBlock, + const vtkm::cont::ArrayHandle& 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& 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 +HierarchicalHyperSweeper::HierarchicalHyperSweeper( + vtkm::Id blockId, + const HierarchicalContourTree& hierarchicalTree, + const MeshType& baseBlock, + const vtkm::cont::ArrayHandle& sweepValues) + : HierarchicalTree(hierarchicalTree) + , BaseBlock(baseBlock) + , BlockId(blockId) + , SweepValues(sweepValues) +{ // constructor + // Initalize arrays with 0s + vtkm::cont::ArrayHandleConstant 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 +void HierarchicalHyperSweeper::InitializeRegularVertexCount( + const HierarchicalContourTree& 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(static_cast(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 +void HierarchicalHyperSweeper::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 +void HierarchicalHyperSweeper::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 sweepValuesView( + this->SweepValues, // subset SweepValues + firstSupernode, // start at firstSupernode + numValuesToCopy); // until lastSuperNode (not inclued) + // Target array + vtkm::cont::ArrayHandleView + 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 supernodeIndex( + firstSupernode, static_cast(1), numValuesToProcess); + vtkm::cont::ArrayHandleView + hierarchicalTreeSuperarcsView( + this->HierarchicalTree.Superarcs, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + hierarchicalTreeHyperparentsView( + this->HierarchicalTree.Hyperparents, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + hierarchicalTreeHypernodesView( + this->HierarchicalTree.Hypernodes, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView sweepValuesView( + this->SweepValues, firstSupernode, numValuesToProcess); + // create the worklet + vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper:: + ComputeSuperarcDependentWeightsWorklet + 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 +void HierarchicalHyperSweeper::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 supernodeIndex( + firstSupernode, static_cast(1), numValuesToProcess); + vtkm::cont::ArrayHandleView + hierarchicalTreeSupernodesView( + this->HierarchicalTree.Supernodes, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + hierarchicalTreeSuperarcsView( + this->HierarchicalTree.Superarcs, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + 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 + 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 + sortedTransferTargetView(this->SortedTransferTarget, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + 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 + 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 +void HierarchicalHyperSweeper::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 + 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 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 supernodeIndex( + firstSupernode, static_cast(1), numValuesToProcess); + vtkm::cont::ArrayHandleView + sortedTransferTargetView(this->SortedTransferTarget, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + sortedTransferTargetShiftedView( + this->SortedTransferTarget, firstSupernode + 1, numValuesToProcess); + vtkm::cont::ArrayHandleView + valuePrefixSumView(this->ValuePrefixSum, firstSupernode, numValuesToProcess); + vtkm::cont::ArrayHandleView + 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 +std::string HierarchicalHyperSweeper::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 +void HierarchicalHyperSweeper::SaveHierarchicalContourTreeDot( + std::string message, + const char* outFileName) const +{ // SaveHierarchicalContourTreeDot() + std::string hierarchicalTreeDotString = + HierarchicalContourTreeDotGraphPrint( + 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 diff --git a/vtkm/worklet/contourtree_distributed/TreeGrafter.h b/vtkm/worklet/contourtree_distributed/TreeGrafter.h index 967cb1966..a60eba2d8 100644 --- a/vtkm/worklet/contourtree_distributed/TreeGrafter.h +++ b/vtkm/worklet/contourtree_distributed/TreeGrafter.h @@ -404,7 +404,10 @@ void TreeGrafter::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(0), vtkm::Add()); // if there are any at all, we need an extra iteration if (numAttachmentPoints > 0) diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/CMakeLists.txt b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/CMakeLists.txt new file mode 100644 index 000000000..59c2fae73 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/CMakeLists.txt @@ -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}) diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcDependentWeightsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcDependentWeightsWorklet.h new file mode 100644 index 000000000..e0ec6c3ee --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcDependentWeightsWorklet.h @@ -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 +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_hyper_sweeper +{ + +/// Worklet used in HierarchicalHyperSweeper.ComputeSuperarcDependentWeightsWorklet(...) to +/// compute the superarc dependent weights +template +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 + 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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcTransferWeightsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcTransferWeightsWorklet.h new file mode 100644 index 000000000..8a4657a3b --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/ComputeSuperarcTransferWeightsWorklet.h @@ -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 +#include + +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 + 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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountComputeSuperparentIdsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountComputeSuperparentIdsWorklet.h new file mode 100644 index 000000000..c44c0a70e --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountComputeSuperparentIdsWorklet.h @@ -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 +#include + +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 + 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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountInitalizeCountsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountInitalizeCountsWorklet.h new file mode 100644 index 000000000..b06892fc5 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountInitalizeCountsWorklet.h @@ -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 +#include + +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 + 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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountSubtractLowEndWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountSubtractLowEndWorklet.h new file mode 100644 index 000000000..764f5d0e0 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/InitializeRegularVertexCountSubtractLowEndWorklet.h @@ -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 +#include + +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 + 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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferTargetComperator.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferTargetComperator.h new file mode 100644 index 000000000..e5ba71632 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferTargetComperator.h @@ -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 +#include + +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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateLHEWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateLHEWorklet.h new file mode 100644 index 000000000..51c66ecf9 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateLHEWorklet.h @@ -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 +#include + +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 diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateRHEWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateRHEWorklet.h new file mode 100644 index 000000000..a761b54b3 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_hyper_sweeper/TransferWeightsUpdateRHEWorklet.h @@ -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 +#include + +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