From 9dbccaae1d90101bcd85ca5dbaadfefb4034b777 Mon Sep 17 00:00:00 2001 From: Oliver Ruebel Date: Sun, 21 Mar 2021 01:46:01 -0700 Subject: [PATCH] Port/implement HierarchicalAugmenter --- vtkm/filter/ContourTreeUniformDistributed.hxx | 1 + .../contourtree_distributed/CMakeLists.txt | 2 + .../HierarchicalAugmenter.h | 1311 +++++++++++++++++ .../HierarchicalHyperSweeper.h | 1 + .../AttachmentAndSupernodeComparator.h | 202 +++ .../AttachmentSuperparentAndIndexComparator.h | 187 +++ .../hierarchical_augmenter/CMakeLists.txt | 28 + .../CopyBaseRegularStructureWorklet.h | 166 +++ .../CreateSuperarcsWorklet.h | 445 ++++++ .../FindSuperparentForNecessaryNodesWorklet.h | 210 +++ .../IsAscendingDecorator.h | 94 ++ .../IsAttachementPointNeededPredicate.h | 143 ++ .../IsAttachementPointPredicate.h | 141 ++ .../NotNoSuchElementPredicate.h | 89 ++ .../ResizeArraysBuildNewSupernodeIdsWorklet.h | 135 ++ .../SetFirstAttachmentPointInRoundWorklet.h | 146 ++ .../SetSuperparentSetDecorator.h | 94 ++ ...yperstructureSetHyperarcsAndNodesWorklet.h | 153 ++ ...ateHyperstructureSetSuperchildrenWorklet.h | 135 ++ 19 files changed, 3683 insertions(+) create mode 100644 vtkm/worklet/contourtree_distributed/HierarchicalAugmenter.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentAndSupernodeComparator.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentSuperparentAndIndexComparator.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CMakeLists.txt create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CopyBaseRegularStructureWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CreateSuperarcsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/FindSuperparentForNecessaryNodesWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAscendingDecorator.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointNeededPredicate.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointPredicate.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/NotNoSuchElementPredicate.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/ResizeArraysBuildNewSupernodeIdsWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetFirstAttachmentPointInRoundWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetSuperparentSetDecorator.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetHyperarcsAndNodesWorklet.h create mode 100644 vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetSuperchildrenWorklet.h diff --git a/vtkm/filter/ContourTreeUniformDistributed.hxx b/vtkm/filter/ContourTreeUniformDistributed.hxx index bb1f38f4b..25d06b9ef 100644 --- a/vtkm/filter/ContourTreeUniformDistributed.hxx +++ b/vtkm/filter/ContourTreeUniformDistributed.hxx @@ -75,6 +75,7 @@ #include +#include #include // DIY includes diff --git a/vtkm/worklet/contourtree_distributed/CMakeLists.txt b/vtkm/worklet/contourtree_distributed/CMakeLists.txt index 26a5b56e1..ff7e37069 100644 --- a/vtkm/worklet/contourtree_distributed/CMakeLists.txt +++ b/vtkm/worklet/contourtree_distributed/CMakeLists.txt @@ -16,6 +16,7 @@ set(headers DistributedContourTreeBlockData.h HierarchicalContourTree.h HierarchicalHyperSweeper.h + HierarchicalAugmenter.h InteriorForest.h MergeBlockFunctor.h MultiBlockContourTreeHelper.h @@ -31,3 +32,4 @@ add_subdirectory(boundary_tree_maker) add_subdirectory(tree_grafter) add_subdirectory(hierarchical_contour_tree) add_subdirectory(hierarchical_hyper_sweeper) +add_subdirectory(hierarchical_augmenter) diff --git a/vtkm/worklet/contourtree_distributed/HierarchicalAugmenter.h b/vtkm/worklet/contourtree_distributed/HierarchicalAugmenter.h new file mode 100644 index 000000000..1224cab00 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/HierarchicalAugmenter.h @@ -0,0 +1,1311 @@ +//============================================================================ +// 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 +// +// HierarchicalAugmenter.h +// +//======================================================================================= +// +// COMMENTS: +// +// In order to compute geometric measures properly, we probably need to have all supernodes +// inserted rather than the lazy insertion implicit in the existing computation. After discussion, +// we have decided to make this a post-processing step in order to keep our options open. +// +// Fortunately, the HierarchicalContourTree structure will hold a tree augmented with lower level +// supernodes, so we just want a factory class that takes a HCT as input and produces another one +// as output. Note that the output will no longer have insertions to be made, as all subtrees will +// be rooted at a supernode in the parent level. +// +// Since this is blockwise, we will have the main loop external (as with the HierarchicalHyperSweeper) +// and have it invoke subroutines here +// +// The processing will be based on a fanin with partners as usual +// I. Each block swaps all attachment points for the level with its partner +// II. Fanning-in builds sets of all attachment points to insert into each superarc except the base level +// III.At the end of the fanin, we know the complete set of all supernodes to be inserted in all superarcs, +// so we insert them all at once & renumber. We should not need to do so in a fan-out +// +// After some prototyping in Excel, the test we will need to apply is the following: +// +// In round N, we transfer all attachment points whose round is < N+1 and whose superparent round is >= N+1 +// (NB: In excel, I started with Round 1, when I should have started with round 0 to keep the swap-partner correct) +// +// The superparent round is the round at which the attachment point will be inserted at the end, so the +// attachment point needs to be shared at all levels up to and including that round, hence the second branch +// of the test. +// +// The first branch is because the attachment points at round N are already represented in the partner +// due to the construction of the hierarchical contour tree. Therefore transferring them is redundant and +// complicates processing, so we omit them. For higher levels, they will need to be inserted. +// +// This test is independent of things such as sort order, so we can keep our arrays in unsorted order. +// We may wish to revisit this later to enforce a canonical order for validation / verification +// but as long as we are consistent, we should in fact have a canonical ordering on each block. +// +//======================================================================================= + +#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ + +/// Facture class for augmenting the hierarchical contour tree to enable computations of measures, e.g., volumne +template +class HierarchicalAugmenter +{ // class HierarchicalAugmenter +public: + /// the tree that it hypersweeps over + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* BaseTree; + /// the tree that it is building + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* AugmentedTree; + + /// the ID of the base block (used for debug output) + vtkm::Id BlockId; + + /// arrays storing the details for the attachment points & old supernodes the Id in the global data set + vtkm::worklet::contourtree_augmented::IdArrayType GlobalRegularIds; + + /// the data value + vtkm::cont::ArrayHandle DataValues; + + /// the supernode index + /// when we swap attachment points, we will set this to NO_SUCH_ELEMENT because the supernodes + /// added are on a different block, so their original supernodeId becomes invalid + vtkm::worklet::contourtree_augmented::IdArrayType SupernodeIds; + + /// the superarc will *ALWAYS* be -1 for a true attachment point, so we don't store it + /// instead, the superparent stores the Id for the arc it inserts into + /// WARNING: in order for sorting to work, we will need to carry forward the ascending / descending flag + /// This flag is normally stored on the superarc, but will be stored in this class on the superparent + vtkm::worklet::contourtree_augmented::IdArrayType Superparents; + + /// we want to track the round on which the superparent is transferred (we could look it up, but it's + /// more convenient to have it here). Also, we don't need the iteration. + vtkm::worklet::contourtree_augmented::IdArrayType SuperparentRounds; + + /// we also want to track the round on which the attachment point was originally transferred + vtkm::worklet::contourtree_augmented::IdArrayType WhichRounds; + + /// if we're not careful, we'll have read-write conflicts when swapping with the partner + /// there are other solutions, but the simpler solution is to have a transfer buffer for + /// the set we want to send - which means another set of parallel arrays + vtkm::worklet::contourtree_augmented::IdArrayType OutGlobalRegularIds; + vtkm::cont::ArrayHandle OutDataValues; + vtkm::worklet::contourtree_augmented::IdArrayType OutSupernodeIds; + vtkm::worklet::contourtree_augmented::IdArrayType OutSuperparents; + vtkm::worklet::contourtree_augmented::IdArrayType OutSuperparentRounds; + vtkm::worklet::contourtree_augmented::IdArrayType OutWhichRounds; + + /// these are essentially temporary local variables, but are placed here to make the DebugPrint() + /// more comprehensive. They will be allocated where used + /// this one makes a list of attachment Ids and is used in sevral different places, so resize it when done + vtkm::worklet::contourtree_augmented::IdArrayType AttachmentIds; + /// tracks segments of attachment points by round + vtkm::worklet::contourtree_augmented::IdArrayType FirstAttachmentPointInRound; + /// maps from old supernode Id to new supernode Id + vtkm::worklet::contourtree_augmented::IdArrayType NewSupernodeIds; + /// tracks which supernodes are kept in a given round + vtkm::worklet::contourtree_augmented::IdArrayType KeptSupernodes; + /// sorting array & arrays for data details + vtkm::worklet::contourtree_augmented::IdArrayType SupernodeSorter; + vtkm::worklet::contourtree_augmented::IdArrayType GlobalRegularIdSet; + vtkm::cont::ArrayHandle DataValueSet; + vtkm::worklet::contourtree_augmented::IdArrayType SuperparentSet; + vtkm::worklet::contourtree_augmented::IdArrayType SupernodeIdSet; + /// data for transferring regular nodes + vtkm::worklet::contourtree_augmented::IdArrayType RegularSuperparents; + vtkm::worklet::contourtree_augmented::IdArrayType RegularNodesNeeded; + + /// empty constructor + HierarchicalAugmenter() {} + + /// initializer (called explicitly after constructor) + void Initialize( + vtkm::Id blockId, + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* inBaseTree, + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* inAugmentedTree); + + /// routine to prepare the set of attachment points to transfer + void PrepareOutAttachmentPoints(vtkm::Id round); + + /// routine to retrieve partner's current list of attachment points + void RetrieveInAttachmentPoints(HierarchicalAugmenter& partner); + + /// routine to release memory used for out arrays + void ReleaseOutArrays(); + + /// routine to reconstruct a hierarchical tree using the augmenting supernodes + void BuildAugmentedTree(); + + // subroutines for BuildAugmentedTree + /// initial preparation + void PrepareAugmentedTree(); + /// transfer of hyperstructure but not superchildren count + void CopyHyperstructure(); + /// transfer level of superstructure with insertions + void CopySuperstructure(); + /// reset the super Ids in the hyperstructure to the new values + void UpdateHyperstructure(); + /// copy the remaining base level regular nodes + void CopyBaseRegularStructure(); + + // subroutines for CopySuperstructure + /// gets a list of all the old supernodes to transfer at this level (ie except attachment points + void RetrieveOldSupernodes(vtkm::Id roundNumber); + /// resizes the arrays for the level + void ResizeArrays(vtkm::Id roundNumber); + /// adds a round full of superarcs (and regular nodes) to the tree + void CreateSuperarcs(vtkm::Id roundNumber); + + /// debug routine + std::string DebugPrint(std::string message, const char* fileName, long lineNum); + +private: + /// Used internally to Invoke worklets + vtkm::cont::Invoker Invoke; + +}; // class HierarchicalAugmenter + + + +// initalizating function +template +void HierarchicalAugmenter::Initialize( + vtkm::Id blockId, + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* baseTree, + vtkm::worklet::contourtree_distributed::HierarchicalContourTree* augmentedTree) +{ // Initialize() + // copy the parameters for use + this->BlockId = blockId; + this->BaseTree = baseTree; + this->AugmentedTree = augmentedTree; + + // now construct a list of all attachment points on the block + // to do this, we construct an index array with all supernode ID's that satisfy: + // 1. superparent == NO_SUCH_ELEMENT (i.e. root of interior tree) + // 2. round < nRounds (except the top level, where 1. indicates the tree root) + // initalize AttachementIds + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::IsAttachementPointPredicate + isAttachementPointPredicate( + this->BaseTree->Superarcs, this->BaseTree->whichRound, this->BaseTree->NumRounds); + vtkm::cont::Algorithm::CopyIf( + // first we generate a list of all of the supernodes + vtkm::cont::ArrayHandleIndex(this->BaseTree->Supernodes.GetNumberOfValues()), + // then our stencil identifies all attachment points + // i.e., an attachment point is defined by having no superarc (NO_SUCH_ELEMENT) and not + // being in the final round (where this indicates the global root) defined by the condition + // if (noSuchElement(baseTree->superarcs[supernode]) && (baseTree->whichRound[supernode] < baseTree->nRounds)) + isAttachementPointPredicate, + // And the CopyIf compress the supernodes array to eliminate the non-attachement points and + // save to this->AttachmentIds + this->AttachmentIds); + } + + // we now resize the working arrays + this->GlobalRegularIds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->DataValues.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->SupernodeIds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->Superparents.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->SuperparentRounds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->WhichRounds.Allocate(this->AttachmentIds.GetNumberOfValues()); + + // and do an indexed copy (permutation) to copy in the attachment point information + { + auto hierarchicalRegularIds = + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->BaseTree->Supernodes); + auto superparents = + vtkm::cont::make_ArrayHandlePermutation(hierarchicalRegularIds, this->BaseTree->Superparents); + // globalRegularIDs[attachmentPoint] = baseTree->regularNodeGlobalIDs[hierarchicalRegularID]; + vtkm::cont::Algorithm::Copy(vtkm::cont::make_ArrayHandlePermutation( + hierarchicalRegularIds, BaseTree->RegularNodeGlobalIds), + this->GlobalRegularIds); + //dataValues[attachmentPoint] = baseTree->dataValues [hierarchicalRegularID]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(hierarchicalRegularIds, BaseTree->DataValues), + this->DataValues); + //supernodeIDs[attachmentPoint] = supernodeID; + vtkm::cont::Algorithm::Copy(this->AttachmentIds, // these are our supernodeIds + this->SupernodeIds); + //superparentRounds[attachmentPoint] = baseTree->whichRound [superparent]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(superparents, this->BaseTree->WhichRound), + this->SuperparentRounds); + //whichRounds[attachmentPoint] = baseTree->whichRound[supernodeID]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->baseTree->WhichRound), + this->WhichRounds); + + // get the ascending flag from the superparent's superarc and transfer to the superparent + // Array decorator to add the IS_ASCENDING flag to our superparent, i.e., + // if (isAscending(baseTree->superarcs[superparent])){ superparent |= IS_ASCENDING; } + auto isAscendingSuperparentArr = vtkm::cont::make_ArrayHandleDecorator( + superparents.GetNumberOfValues(), + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::IsAscendingDecorator{}, + superparents, + this->BaseTree->Superarcs); + vtkm::cont::Algorithm::Copy(isAscendingSuperparentArr, superparents); + } + + // clean up memory + this->AttachmentIds.ReleaseResources(); +} // Initialize() + + + +// routine to prepare the set of attachment points to transfer +template +void HierarchicalAugmenter::PrepareOutAttachmentPoints(vtkm::Id round) +{ // PrepareOutAttachmentPoints() + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + IsAttachementPointNeededPredicate isAttachementPointNeededPredicate( + this->SuperparentRounds, this->WhichRounds, round); + vtkm::cont::Algorithm::CopyIf( + // 1. generate a list of all of the attachment points + vtkm::cont::ArrayHandleIndex(this - GlobalRegularIds.GetNumberOfValues()), + // 2. then our stencil identifies all attachment points needed + isAttachementPointNeededPredicate, + // 3. And the CopyIf compress the supernodes array to eliminate the non-attachement points and + // save to this->AttachmentIds + this->AttachmentIds); + } + + // 4. resize the out array + this->OutGlobalRegularIds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->OutDataValues.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->OutSupernodeIds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->OutSuperparents.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->OutSuperparentRounds.Allocate(this->AttachmentIds.GetNumberOfValues()); + this->OutWhichRounds.Allocate(this->AttachmentIds.GetNumberOfValues()); + + // 5. copy the points we want + { + // outGlobalRegularIDs[outAttachmentPoint] = globalRegularIDs[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->GlobalRegularIds), + this->OutGlobalRegularIds); + // outDataValues[outAttachmentPoint] = dataValues[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->DataValues), + this->outDataValues); + // outSupernodeIDs[outAttachmentPoint] = supernodeIDs[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->SupernodeIds), + this->OutSupernodeIds); + // outSuperparents[outAttachmentPoint] = superparents[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->superparents), + this->outSuperparents); + // outSuperparentRounds[outAttachmentPoint] = superparentRounds[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->SuperparentRounds), + this->outSuperparentRounds); + // outWhichRounds[outAttachmentPoint] = whichRounds[attachmentPoint]; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandlePermutation(this->AttachmentIds, this->WhichRounds), + this->OutWhichRounds); + } + + // clean up memory + this->AttachmentIds.ReleaseResources(); +} // PrepareOutAttachmentPoints() + + +// routine to add partner's current list of attachment points +template +void HierarchicalAugmenter::RetrieveInAttachmentPoints(HierarchicalAugmenter& partner) +{ // RetrieveInAttachmentPoints() + // what we want to do here is to copy all of the partner's attachments for the round into our own buffer + // this code will be replaced in the MPI with a suitable transmit / receive + // store the current size + vtkm::Id numAttachmentsCurrently = this->GlobalRegularIds.GetNumberOfValues(); + vtkm::Id numIncomingAttachments = partner.OutGlobalRegularIds.GetNumberOfValues(); + vtkm::Id numTotalAttachments = numAttachmentsCurrently + numIncomingAttachments; + + // I. resize the existing arrays + this->GlobalRegularIDs.Allocate(numTotalAttachments); + this->DataValues.Allocate(numTotalAttachments); + this->SupernodeIDs.Allocate(numTotalAttachments); + this->Superparents.Allocate(numTotalAttachments); + this->SuperparentRounds.Allocate(numTotalAttachments); + this->WhichRounds.Allocate(numTotalAttachments); + + // II. copy the additional points into them + { + // The following sequence of copy operations implements the following for from the orginal code + // for (vtkm::Id outAttachmentPoint = 0; outAttachmentPoint < partner.outGlobalRegularIDs.size(); outAttachmentPoint++) + // globalRegularIDs[attachmentPoint] = partner.outGlobalRegularIDs[outAttachmentPoint]; + vtkm::cont::Algorithm::Copy(partner.OutGlobalRegularIds, + vtkm::cont::make_ArrayHandleView(this->GlobalRegularIds, + numAttachmentsCurrently, + numIncomingAttachments)); + // dataValues[attachmentPoint] = partner.outDataValues[outAttachmentPoint]; + vtkm::cont::Algorithm::Copy(partner.OutDataValues, + vtkm::cont::make_ArrayHandleView(this->DataValues, + numAttachmentsCurrently, + numIncomingAttachments)); + // supernodeIDs[attachmentPoint] = NO_SUCH_ELEMENT; + vtkm::cont::Algorithm::Copy( + vtkm::cont::make_ArrayHandleConstant(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, + numIncomingAttachments), + vtkm::cont::make_ArrayHandleView( + this->SupernodeIds, numAttachmentsCurrently, numIncomingAttachments)); + // superparents[attachmentPoint] = partner.outSuperparents[outAttachmentPoint]; + vtkm::cont::Algorithm::Copy(partner.outSuperparents, + vtkm::cont::make_ArrayHandleView(this->Superparents, + numAttachmentsCurrently, + numIncomingAttachments)); + // superparentRounds[attachmentPoint] = partner.outSuperparentRounds[outAttachmentPoint]; + vtkm::cont::Algorithm::Copy(partner.outSuperparentRounds, + vtkm::cont::make_ArrayHandleView(this->SuperparentRounds, + numAttachmentsCurrently, + numIncomingAttachments)); + // whichRounds[attachmentPoint] = partner.outWhichRounds[outAttachmentPoint]; + vtkm::cont::Algorithm::Copy(partner.OutWhichRounds, + vtkm::cont::make_ArrayHandleView(this->WhichRounds, + numAttachmentsCurrently, + numIncomingAttachments)); + } +} // RetrieveInAttachmentPoints() + + +// routine to release memory used for out arrays +template +void HierarchicalAugmenter::ReleaseOutArrays() +{ // ReleaseOutArrays() + this->OutGlobalRegularIDs.ReleaseResources(); + this->OutDataValues.ReleaseResources(); + this->OutSupernodeIDs.ReleaseResources(); + this->OutSuperparents.ReleaseResources(); + this->OutSuperparentRounds.ReleaseResources(); + this->OutWhichRounds.ReleaseResources(); +} // ReleaseOutArrays() + + +// routine to reconstruct a hierarchical tree using the augmenting supernodes +template +void HierarchicalAugmenter::BuildAugmentedTree() +{ // BuildAugmentedTree() + // 1. Prepare the data structures for filling in, copying in basic information & organising the attachment points + this->PrepareAugmentedTree(); + + // 2. Copy the hyperstructure, using the old super IDs for now + this->CopyHyperstructure(); + + // 3. Copy the superstructure, inserting additional points as we do + this->CopySuperstructure(); + + // 4. Update the hyperstructure to use the new super IDs + this->UpdateHyperstructure(); + + // 5. Copy the remaining regular structure at the bottom level, setting up the regular sort order in the process + this->CopyBaseRegularStructure(); +} // BuildAugmentedTree() + + +// initial preparation +template +void HierarchicalAugmenter::PrepareAugmentedTree() +{ // PrepareAugmentedTree() + // 1. Sort attachment points on superparent round, with secondary sort on global index so duplicates appear next to each other + // This can (and does) happen when a vertex on the boundary is an attachment point separately for multiple blocks + // We add a tertiary sort on supernode ID so that on each block, it gets the correct "home" supernode ID for reconciliation + //: note that we use a standard comparator that tie breaks with index. This separates into + // segments with identical superparent round, which is all we need for now + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleIndex(this->GlobalRegularIds.GetNumberOfValues), this->AttachmentIds); + + // 1a. We now need to suppress duplicates, + { + // Sort the attachement Ids + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + AttachmentSuperparentAndIndexComparator attachmentSuperparentAndIndexComparator( + this->SuperparentRounds, this->GlobalRegularIds, this->SupernodeIds); + vtkm::cont::Algorithm::Sort(this->AttachmentIds, attachmentSuperparentAndIndexComparator); + // Remove the duplicate values + vtkm::cont::Algorithm::Unique(this->AttachmentIds); + } + + // 2. Set up array with bounds for subsegments + // We do +2 because the top level is extra, and we need an extra sentinel value at the end + // We initialise to NO_SUCH_ELEMENT because we may have rounds with none and we'll need to clean up serially (over the number of rounds, i.e. lg n) + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, + this->BaseTree->NumRounds + 2), + this->FirstAttachmentPointInRound); + + // Now do a parallel set operation + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + SetFirstAttachmentPointInRoundWorklet setFirstAttachmentPointInRoundWorklet; + this->Invoke(setFirstAttachmentPointInRoundWorklet, + this->AttachmentIds, // input + this->SuperparentRounds, // input + this->FirstAttachmentPointInRound); + } + + // The last element in the array is always set to the size as a sentinel value + // We need to pull the firstAttachmentPointInRound array to the control environment + // anyways for the loop afterwards so can do this set here without using Copy + auto firstAttachmentPointInRoundPortal = this - FirstAttachmentPointInRound.WritePortal(); + firstAttachmentPointInRoundPortal.Set(this->BaseTree->nRounds + 1, + this->AttachmentIs.GetNumberOfValues()); + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + this->DebugPrint("First Attachment Point Set Where Possible", __FILE__, __LINE__)); +#endif + + // Now clean up by looping through the rounds (serially - this is logarithmic at worst) + // We loop backwards so that the next up propagates downwards + // WARNING: DO NOT PARALLELISE THIS LOOP + for (vtkm::Id roundNumber = this->BaseTree->NumRounds; roundNumber >= 0; roundNumber--) + { // per round + // if it still holds NSE, there are none in this round, so use the next one up + if (vtkm::worklet::contourtree_augmented::NoSuchElement( + firstAttachmentPointInRoundPortal.Get(roundNumber))) + { + firstAttachmentPointInRoundPortal.Set(roundNumber, + firstAttachmentPointInRoundPortal.Get(roundNumber + 1)); + } + } // per round + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, DebugPrint("Subsegments Identified", __FILE__, __LINE__)); +#endif + + // 3. Initialise an array to keep track of the mapping from old supernode ID to new supernode ID + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, + this->BaseTree->Supernodes.GetNumberOfValues()), + this->NewSupernodeIds); + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + this->DebugPrint("Augmented Tree Prepared", __FILE__, __LINE__)); + +#endif +} // PrepareAugmentedTree() + + +// transfer of hyperstructure but not superchildren count +template +void HierarchicalAugmenter::CopyHyperstructure() +{ // CopyHyperstructure() + // we can also resize some of the additional information + this->AugmentedTree->NumRounds = this->BaseTree->NumRounds; + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant( + static_cast(0), this->BaseTree->NumRegularNodesInRound.GetNumberOfValues()), + this->AugmentedTree->NumRegularNodesInRound); + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant( + static_cast(0), this->BaseTree->NumSupernodesInRound.GetNumberOfValues()), + this->AugmentedTree->NumSupernodesInRound); + + // this chunk needs to be here to prevent the HierarchicalContourTree::DebugPrint() routine from crashing + this->AugmentedTree->FirstSupernodePerIteration.resize( + this->baseTree->FirstSupernodePerIteration.size()); + // this loop doesn't need to be parallelised, as it is a small size: we will fill in values later + for (vtkm::Id roundNumber = 0; + roundNumber < this->AugmentedTree->FirstSupernodePerIteration.GetNumberOfValues(); + roundNumber++) + { + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant( + static_cast(0), + this->BaseTree->FirstSupernodePerIteration[roundNumber].GetNumberOfValues()), + this->AugmentedTree->FirstSupernodePerIteration[roundNumber]); + } + + // hyperstructure is unchanged, so we can copy it + vtkm::cont::Algorithm::Copy(this->BaseTree->NumHypernodesInRound, + this->AugmentedTree->NumHypernodesInRound); + vtkm::cont::Algorithm::Copy(this->BaseTree->NumIterations, this->AugmentedTree->NumIterations); + this->AugmentedTree->FirstHypernodePerIteration.resize( + this->BaseTree->FirstHypernodePerIteration.GetNumberOfValues()); + // this loop doesn't need to be parallelised, as it is a small size + for (vtkm::Id roundNumber = 0; + roundNumber < this->AugmentedTree->FirstHypernodePerIteration.GetNumberOfValues(); + roundNumber++) + { // per round + // duplicate the existing array + vtkm::cont::Algorithm::Copy(this->BaseTree->FirstHypernodePerIteration[roundNumber], + this->AugmentedTree->firstHypernodePerIteration[roundNumber]); + } // per round + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, DebugPrint("Hyperstructure Copied", __FILE__, __LINE__)); +#endif +} // CopyHyperstructure() + + +// transfer level of superstructure with insertions +template +void HierarchicalAugmenter::CopySuperstructure() +{ // CopySuperstructure() + + // Loop from the top down: + for (vtkm::Id roundNumber = this->BaseTree->NumRounds; roundNumber >= 0; roundNumber--) + { // per round + // start by retrieving list of old supernodes from the tree (except for attachment points) + this->RetrieveOldSupernodes(roundNumber); + + // since we know the number of attachment points, we can now allocate space for the level + // and set up arrays for sorting the supernodes + this->ResizeArrays(roundNumber); + + // now we create the superarcs for the round in the new tree + this->CreateSuperarcs(roundNumber); + } // per round + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + this->DebugPrint("Superstructure Copied", __FILE__, __LINE__)); +#endif +} // CopySuperstructure() + + +// reset the super IDs in the hyperstructure to the new values +template +void HierarchicalAugmenter::UpdateHyperstructure() +{ // UpdateHyperstructure() + + // 5. Reset hypernodes, hyperarcs and superchildren using supernode IDs + // The hyperstructure is unchanged, but uses old supernode IDs + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + UpdateHyperstructureSetHyperarcsAndNodesWorklet + updateHyperstructureSetHyperarcsAndNodesWorklet; + this->Invoke( + updateHyperstructureSetHyperarcsAndNodesWorklet, + this->BaseTree->Hypernodes, // input + this->BaseTree->Hyperarcs, // input + this->NewSupernodeIds, // input + this->AugmentedTree->Hypernodes, // output (the array is automatically resized here) + this->AugmentedTree->Hyperarcs // output (the array is automatically resized here) + ); + } + + // finally, find the number of superchildren as the delta between the + // super ID and the next hypernode's super ID + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + UpdateHyperstructureSetSuperchildrenWorklet updateHyperstructureSetSuperchildrenWorklet( + this->AugmentedTree->Supernodes.GetNumberOfValues()); + this->Invoke( + updateHyperstructureSetSuperchildrenWorklet, + this->AugmentedTree->Hypernodes, // input + this->AugmentedTree->Superchildren // output (the array is automatically resized here) + ); + } +} // UpdateHyperstructure() + + +// copy the remaining base level regular nodes +template +void HierarchicalAugmenter::CopyBaseRegularStructure() +{ // CopyBaseRegularStructure() + // 6. Set up the regular node sorter for the final phase + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleIndex(this->AugmentedTree->RegularNodeGlobalIds.GetNumberOfValues()), + this->AugmentedTree->RegularNodeSortOrder); + { + vtkm::worklet::contourtree_distributed::PermuteComparator // hierarchical_contour_tree:: + permuteComparator(this->AugmentedTree->RegularNodeGlobalIds); + vtkm::cont::Algorithm::Sort(this->AugmentedTree->RegularNodeSortOrder, permuteComparator); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint("Regular Node Sorter Sorted", __FILE__, __LINE__)); +#endif + + // 7. Cleanup at level = 0. The principal task here is to insert all of the regular + // nodes in the original block into the regular arrays. The problem is that we + // haven't got a canonical list of them since in the original hierarchical tree, + // they might have been passed upwards as part of the boundary resolution. We + // now have a choice: we can take all "unfiled" regular nodes in the original hierarchical + // tree, or we can return to the block of data. The difference here is that the + // "unfiled" regular nodes can include nodes from other blocks which were passed up + // and retained in both partners. On the other hand, we already have the list of + // unfiled regular nodes, so the overhead for using them is not huge. And if we + // return to the block, we will need to pass it in as a parameter and template + // on mesh type. So, for the purposes of tidy coding, I shall use the first + // option, which means that not all of the Level 0 regular nodes belong to the block. + + { + // For each regular node, if it hasn't been transferred to the new tree, search for the superarc to which it belongs + // default the superparent to NO_SUCH_ELEMENT to use as a flag for "we can ignore it" + // now loop, finding the superparent for each node needed and set the approbriate value or set to + // NO_SUCH_ELEMENT if not needed. The worklet also automatically sized our arrays + // temporary array so we can stream compact (aka CopyIf) afterwards + vtkm::worklet::contourtree_augmented::IdArrayType tempRegularNodesNeeded; + // create the worklet + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + FindSuperparentForNecessaryNodesWorklet findSuperparentForNecessaryNodesWorklet; + // Get a FindRegularByGlobal and FindSuperArcForUnknownNode execution object for our worklet + auto findRegularByGlobal = this->AugmentedTree->GetFindRegularByGlobal(); + auto findSuperArcForUnknownNode = this->AugmentedTree->GetFindSuperArcForUnknownNode(); + + // excute the worklet + this->Invoke(findSuperparentForNecessaryNodesWorklet, // the worklet to call + // inputs + this->BaseTree->RegularNodeGlobalIds, // input domain + this->BaseTree->Superparents, // input + this->BaseTree->DataValues, // input + this->BaseTree->Superarcs, // input + this->NewSupernodeIds, // input + // Execution objects from the AugmentedTree + findRegularByGlobal, + findSuperArcForUnknownNode, + // Output arrays to populate + this->RegularSuperparents, // output + tempRegularNodesNeeded // output. will be CopyIf'd to this->RegularNodesNeeded + ); + + // We now compress to get the set of nodes to transfer. I.e., remove all + // NO_SUCH_ELEMENT entires and copy the values to keep to our proper arrays + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::NotNoSuchElementPredicate + notNoSuchElementPredicate; + vtkm::cont::Algorithm::CopyIf( + tempRegularNodesNeeded, // input data + tempRegularNodesNeeded, // stencil (same as input) + this->RegularNodesNeeded, // target array (will be resized) + notNoSuchElementPredicate // predicate returning true of element is NOT NO_SUCH_ELEMENT + ); + } + + // resize the regular arrays to fit + vtkm::Id numRegNeeded = this->RegularNodesNeeded.GetNumberOfValues(); + vtkm::Id numExistingRegular = this->AugmentedTree->rRgularNodeGlobalIDs.GetNumberOfValues(); + vtkm::Id numTotalRegular = numExistingRegular + numRegNeeded; + this->AugmentedTree->RegularNodeGlobalIds.Allocate(numTotalRegular); + this->AugmentedTree->DataValues.Allocate(numTotalRegular); + this->AugmentedTree->RegularNodeSortOrder.Allocate(numTotalRegular); + this->AugmentedTree->Superparents.Allocate(numTotalRegular); + // since these are *ALL* only regular nodes, setting this->AugmentedTree->Regular2Supernode is easy: + vtkm::cont::Algorithm::Copy( + vtkm::cont::ArrayHandleConstant(vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, + numTotalRegular), + this->AugmentedTree->Regular2Supernode); + + // OK: we have a complete list of the nodes to transfer. Since we make no guarantees (yet) about sorting, they just copy across + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::CopyBaseRegularStructureWorklet + copyBaseRegularStructureWorklet(numExistingRegular); + // NOTE: We require the input arrays (aside form the input domain) to be permutted by the + // regularNodesNeeded input domain so that we can use FieldIn instead of WholeArrayIn + // NOTE: We require ArrayHandleView for the output arrays of the range [numExistingRegular:end] so + // that we can use FieldOut instead of requiring WholeArrayInOut + // input domain for the worklet of [0, regularNodesNeeded.GetNumberOfValues()] + auto regularNodesNeededRange = + vtkm::cont::ArrayHandleIndex(this->RegularNodesNeeded.GetNumberOfValues()); + // input baseTree->regularNodeGlobalIds permuted by regularNodesNeeded + auto baseTreeRegularNodeGlobalIdsPermuted = vtkm::cont::make_ArrayHandlePermutation( + this->RegularNodesNeeded, this->BaseTree->RegularNodeGlobalIds); + // input baseTree->dataValues permuted by regularNodesNeeded + auto baseTreeDataValuesPermuted = + vtkm::cont::make_ArrayHandlePermutation(this->RegularNodesNeeded, this->BaseTree->DataValues); + // input regularSuperparents permuted by regularNodesNeeded + auto regularSuperparentsPermuted = + vtkm::cont::make_ArrayHandlePermutation(this->RegularNodesNeeded, this->RegularSuperparents); + // input view of augmentedTree->regularNodeGlobalIds[numExistingRegular:] + auto augmentedTreeRegularNodeGlobalIdsView = + vtkm::cont::make_ArrayHandleView(this->AugmentedTree->RegularNodeGlobalIds, + numExistingRegular, // start writing at numExistingRegular + numRegNeeded); // fill until the end + // input view of augmentedTree->dataValues[numExistingRegular:] + auto augmentedTreeDataValuesView = + vtkm::cont::make_ArrayHandleView(this->AugmentedTree->DataValues, + numExistingRegular, // start writing at numExistingRegular + numRegNeeded); // fill until the end + // input view of augmentedTree->superparents[numExistingRegular:] + auto augmentedTreeSuperparentsView = + vtkm::cont::make_ArrayHandleView(this->AugmentedTree->Superparents, + numExistingRegular, // start writing at numExistingRegular + numRegNeeded); // fill until the end + // input view of augmentedTree->regularNodeSortOrder[numExistingRegular:] + auto augmentedTreeRegularNodeSortOrderView = + vtkm::cont::make_ArrayHandleView(this->AugmentedTree->RegularNodeSortOrderView, + numExistingRegular, // start writing at numExistingRegular + numRegNeeded); // fill until the end + this->Invoke(copyBaseRegularStructureWorklet, // worklet to call + regularNodesNeededRange, // input domain + baseTreeRegularNodeGlobalIdsPermuted, // input + baseTreeDataValuesPermuted, // input + regularSuperparentsPermuted, // input + augmentedTreeRegularNodeGlobalIdsView, // output + augmentedTreeDataValuesView, // output + augmentedTreeSuperparentsView, // output + augmentedTreeRegularNodeSortOrderView // output + ); + } + + // Finally, we resort the regular node sort order + { + vtkm::worklet::contourtree_distributed::PermuteComparator // hierarchical_contour_tree:: + permuteComparator(this->AugmentedTree->RegularNodeGlobalIds); + vtkm::cont::Algorithm::Sort(this->AugmentedTree->RegularNodeSortOrder, permuteComparator); + } +} // CopyBaseRegularStructure() + + +// subroutines for CopySuperstructure +// gets a list of all the old supernodes to transfer at this level (ie except attachment points +template +void HierarchicalAugmenter::RetrieveOldSupernodes(vtkm::Id roundNumber) +{ // RetrieveOldSupernodes() + // a. Transfer supernodes from same level of old tree minus attachment points, storing by global regular ID not regular ID + // Use compression to get the set of supernode IDs that we want to keep + // TODO PERFORMANCE STATISTICS: + // the # of supernodes at each level minus the # of kept supernodes gives us the # of attachment points we lose at this level + // in addition to this, the firstAttachmentPointInRound array gives us the # of attachment points we gain at this level + vtkm::Id supernodeIndexBase = + vtkm::cont::ArrayGetValue(0, this->BaseTree->FirstSupernodePerIteration[roundNumber]); + vtkm::cont::ArrayHandleCounting supernodeIdVals( + supernodeIndexBase, // start + 1, // step + this->KeptSupernodes.GetNumberOfValues() // array size + ); + // the test for whether to keep it is: + // a1. at the top level, keep everything + if (!(roundNumber < this->BaseTree->NumRounds)) + { + vtkm::cont::Algorithm::Copy(supernodeIdVals, this->KeptSupernodes); + } + // a2. at lower levels, keep them if the superarc is NO_SUCH_ELEMENT + else + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::NotNoSuchElementPredicate + notNoSuchElementPredicate; + vtkm::cont::Algorithm::CopyIf( + // first we generate a list of supernodeIds + supernodeIdVals, + // Stencil with baseTree->superarcs[supernodeID] + vtkm::cont::make_ArrayHandleView( + this->BaseTree->Superarcs, supernodeIndexBase, this->KeptSupernodes.GetNumberOfValues()), + // And the CopyIf compresses the array to eliminate unnecssary elements + // save to this->KeptSupernodes + this->KeptSupernodes, + // then our predicate identifies all necessary points. These are all points that suffice the condition + // vtkm::Id supernodeID = keptSupernode + supernodeIndexBase; + // !noSuchElement(baseTree->superarcs[supernodeID]); + notNoSuchElementPredicate); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Old Supernodes Retrieved"), + __FILE__, + __LINE__)); +#endif +} // RetrieveOldSupernodes() + + +// resizes the arrays for the level +template +void HierarchicalAugmenter::ResizeArrays(vtkm::Id roundNumber) +{ // ResizeArrays() + // at this point, we know how many supernodes are kept from the same level of the old tree + // we can also find out how many supernodes are being inserted, which gives us the correct amount to expand by, saving a double resize() call + // note that some of these arrays could probably be resized later, but it's cleaner this way + // also note that if it becomes a problem, we could resize all of the arrays to baseTree->supernodes.size() + # of attachmentPoints as an over-estimate + // then cut them down at the end. The code would however be even messier if we did so + vtkm::Id numSupernodesAlready = this->AugmentedTree->Supernodes.GetNumberOfValues(); + vtkm::Id numInsertedSupernodes = + vtkm::cont::ArrayGetValue(roundNumber + 1, this->FirstAttachmentPointInRound) - + vtkm::cont::ArrayGetValue(roundNumber, this->FirstAttachmentPointInRound); + vtkm::Id numSupernodesThisLevel = + numInsertedSupernodes + this->KeptSupernodes.GetNumberOfValues(); + vtkm::Id newSupernodeCount = numSupernodesAlready + numSupernodesThisLevel; + + // conveniently, the value numSupernodesThisLevel is the number of supernodes *!AND!* regular nodes to store for the round + // TODO: These calls could be changed to avoid potential device copy, but I believe they are actually used + // mainly in the control environment and they should be small arrays, so setting them directly should be Ok. + this->AugmentedTree->NumRegularNodesInRound.WritePortal().Set(roundNumber, + numSupernodesThisLevel); + this->AugmentedTree->NumSupernodesInRound.WritePortal().Set(roundNumber, numSupernodesThisLevel); + this->AugmentedTree->FirstSupernodePerIteration[roundNumber].WritePortal().Set( + 0, numSupernodesAlready); + + // resize the arrays accordingly + { + vtkm::cont::ArrayHandleConstant tempNoSuchElementArr( + vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT, newSupernodeCount); + vtkm::cont::ArrayHandleConstant tempFieldTypeZeroArr(static_cast(0), + newSupernodeCount); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Supernodes); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Superarcs); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Hyperparents); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Super2Hypernode); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->WhichRound); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->WhichIteration); + + // we also know that only supernodes are needed as regular nodes at each level, so we resize those here as well + // we note that it might be possible to update all regular IDs at the end, but leave that optimisation out for now + // therefore we resize the regular-sized arrays as well + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->RegularNodeGlobalIds); + vtkm::cont::Algorithm::Copy(tempFieldTypeZeroArr, this->AugmentedTree->DataValues); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Regular2Supernode); + vtkm::cont::Algorithm::Copy(tempNoSuchElementArr, this->AugmentedTree->Superparents); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S( + vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + std::string(" Arrays Resized"), + __FILE__, + __LINE__)); +#endif + + // The next task is to assemble a sorting array which we will use to construct the new superarcs, containing both the + // kept supernodes and the attachment points. The attachment points are easier since we already have them, so we start + // by allocating space and copying them in: this means another set of arrays for the individual elements. However, we do not + // need all of the data elements, since superparentRound is fixed (and equal to roundNumber inside this loop), and whichRound will be reset + vtkm::cont::Algorithm::Copy(vtkm::cont::ArrayHandleIndex(numSupernodesThisLevel), + this->supernodeSorter); + this->GlobalRegularIDSet.Allocate(numSupernodesThisLevel); + this->DataValueSet.Allocate(numSupernodesThisLevel); + this->SuperparentSet.Allocate(numSupernodesThisLevel); + this->SupernodeIdSet.Allocate(numSupernodesThisLevel); +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Sorter Set Resized"), + __FILE__, + __LINE__)); +#endif + + + // b. Transfer attachment points for level into new supernode array + // to copy them in, we use the existing array of attachment point IDs by round + { + vtkm::Id firstAttachmentPointInRoundCurrent = + vtkm::cont::ArrayGetValue(roundNumber, this->FirstAttachmentPointInRound); + vtkm::Id firstAttachmentPointInRoundNext = + vtkm::cont::ArrayGetValue(roundNumber + 1, this->FirstAttachmentPointInRound); + vtkm::Id currRange = firstAttachmentPointInRoundNext - firstAttachmentPointInRoundCurrent; + auto attachmentPointIdView = + vtkm::cont::make_ArrayHandleView(this->AttachmentIds, // array to subset + firstAttachmentPointInRoundCurrent, // start index + currRange); // count + // Permute the source arrays for the copy + auto globalRegularIdsPermuted = + vtkm::cont::make_ArrayHandlePermutation(attachmentPointIdView, // index array + this->GlobalRegularIds // value array + ); + auto dataValuesPermuted = + vtkm::cont::make_ArrayHandlePermutation(attachmentPointIdView, this->DataValues); + auto superparentsPermuted = + vtkm::cont::make_ArrayHandlePermutation(attachmentPointIdView, this->Superparents); + auto supernodeIdsPermuted = + vtkm::cont::make_ArrayHandlePermutation(attachmentPointIdView, this->SupernodeIds); + // Now use CopySubRange to copy the values into the right places. This allows + // us to place them in the right place and avoid shrinking the array on Copy + vtkm::cont::Algorithm::CopySubRange( + // copy all values of our permutted array + globalRegularIdsPermuted, + 0, + globalRegularIdsPermuted.GetNumberOfValues(), + // copy target + this->GlobalRegularIdSet, + 0); + vtkm::cont::Algorithm::CopySubRange( + dataValuesPermuted, 0, dataValuesPermuted.GetNumberOfValues(), this->DataValueSet, 0); + vtkm::cont::Algorithm::CopySubRange( + superparentsPermuted, 0, superparentsPermuted.GetNumberOfValues(), this->SuperparentSet, 0); + vtkm::cont::Algorithm::CopySubRange( + supernodeIdsPermuted, 0, supernodeIdsPermuted.GetNumberOfValues(), this->SupernodeIdSet, 0); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Attachment Points Transferred"), + __FILE__, + __LINE__)); +#endif + + + // Now we copy in the kept supernodes + { + auto oldRegularIdArr = + vtkm::cont::make_ArrayHandlePermutation(this->KeptSupernodes, // index + this->BaseTree->Supernodes); // values + // Permute the source arrays for the copy + auto baseTreeregularNodeGlobalIdsPermuted = vtkm::cont::make_ArrayHandlePermutation( + oldRegularIdArr, this->BaseTree->RegularNodeGlobalIds); + auto baseTreeDataValuesPermuted = + vtkm::cont::make_ArrayHandlePermutation(oldRegularIdArr, this->BaseTree->DataValues); + + // Now use CopySubRange to copy the values into the right places. This allows + // us to place them in the right place and avoid shrinking the array on Copy + vtkm::cont::Algorithm::CopySubRange(baseTreeregularNodeGlobalIdsPermuted, + 0, + baseTreeregularNodeGlobalIdsPermuted.GetNumberOfValues(), + this->GlobalRegularIdSet, + numInsertedSupernodes); + vtkm::cont::Algorithm::CopySubRange(baseTreeDataValuesPermuted, + 0, + baseTreeDataValuesPermuted.GetNumberOfValues(), + this->DataValueSet, + numInsertedSupernodes); + vtkm::cont::Algorithm::CopySubRange(this->KeptSupernodes, + 0, + this->KeptSupernodes.GetNumberOfValues(), + this->SupernodeIdSet, + numInsertedSupernodes); + // For the last one we need to set values to + // superparentSet[supernodeSetID] = oldSupernodeID | (isAscending(baseTree->superarcs[oldSupernodeID]) ? IS_ASCENDING: 0x00); + // so we use an ArrayHanldeDecorator instead to compute the values and copy them in place + auto setSuperparentSetArrayDecorator = vtkm::cont::make_ArrayHandleDecorator( + this->KeptSupernodes.GetNumberOfValues(), + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::SetSuperparentSetDecorator{}, + this->KeptSupernodes, + this->BaseTree->Superarcs); + vtkm::cont::Algorithm::CopySubRange(setSuperparentSetArrayDecorator, + 0, + this->KeptSupernodes.GetNumberOfValues(), + this->SuperparentSet, + 0); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Kept Supernodes Transferred"), + __FILE__, + __LINE__)); +#endif + + // c. Create a permutation array and sort supernode segment by a. superparent, b. value, d. global index to establish segments (reversing as needed) + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + AttachmentAndSupernodeComparator> + attachmentAndSupernodeComparator( + this->SuperparentSet, this->DataValueSet, this->GlobalRegularIdSet); + vtkm::cont::Algorithm::Sort(this->SupernodeSorter, attachmentAndSupernodeComparator); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Sorter Set Sorted"), + __FILE__, + __LINE__)); +#endif + + // d. Build the inverse permutation array for lookup purposes: + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter:: + ResizeArraysBuildNewSupernodeIdsWorklet resizeArraysBuildNewSupernodeIdsWorklet( + numSupernodesAlready); + auto supernodeIndex = vtkm::cont::ArrayHandleIndex(this->SupernodeSorter.GetNumberOfValues()); + auto supernodeIdSetPermuted = + vtkm::cont::make_ArrayHandlePermutation(this->SupernodeSorter, this->supernodeIdSet); + this->Invoke( + resizeArraysBuildNewSupernodeIdsWorklet, + supernodeIndex, // input domain. We only need the index because supernodeIdSetPermuted already does the permute + supernodeIdSetPermuted, // input input supernodeIDSet permuted by supernodeSorter to allow for FieldIn + this + ->NewSupernodeIds // output/input (both are necessary since not all valyes will be overwritten) + ); + } + +#ifdef DEBUG_PRINT + VTKM_LOG_S(vtkm::cont::LogLevel::Info, + DebugPrint(std::string("Round ") + std::to_string(roundNumber) + + std::string(" Sorting Arrays Built"), + __FILE__, + __LINE__)); +#endif +} // ResizeArrays() + + +// adds a round full of superarcs (and regular nodes) to the tree +template +void HierarchicalAugmenter::CreateSuperarcs(vtkm::Id roundNumber) +{ // CreateSuperarcs() + // retrieve the ID number of the first supernode at this leverl + vtkm::Id numSupernodesAlready = + vtkm::cont::ArrayGetValue(0, this->AugmentedTree->FirstSupernodePerIteration[roundNumber]); + + // e. Connect superarcs for the level & set hyperparents & superchildren count, whichRound, whichIteration, super2hypernode + { + vtkm::worklet::contourtree_distributed::hierarchical_augmenter::CreateSuperarcsWorklet + createSuperarcsWorklet( + numSupernodesAlready, + this->BaseTree->NumRounds, + vtkm::cont::ArrayGetValue(roundNumber, this->AugmentedTree->NumIterations), + roundNumber); + // TODO: The CreateSuperarcsWorklet uses a lot of arrays and lots of WholeArrayTransfers. This could probably be further optimized. + this->Invoke( + createSuperarcsWorklet, // the worklet + this->SupernodeSorter, // input domain (we need access to InputIndex and InputIndex+1) + this->SuperparentSet, // input + this->BaseTree->Superarcs, // input + this->NewSupernodeIds, // input + this->BaseTree->Hyperparents, // input + this->BaseTree->Supernodes, // input + this->BaseTree->RegularNodeGlobalIds, // input + this->GlobalRegularIdSet, // input + this->BaseTree->Super2Hypernode, // input + this->BaseTree->WhichRound, // input + this->BaseTree->WhichIteration, // input + this->DataValueSet, // input + ArrayHandleView(this->AugmentedTree->Superarcs, + this->NumSupernodesAlready, + this->SupernodeSorter.GetNumberOfValues()), // output + this->AugmentedTree->Hyperparents, // input/output + this->AugmentedTree->FirstSupernodePerIteration[roundNumber], // input/output + this->AugmentedTree->Supernodes, // input/output + this->AugmentedTree->Super2hypernode, // input/ouput + this->AugmentedTree->WhichRound, // input/ouput + this->AugmentedTree->WhichIteration, // input/ouput + this->AugmentedTree->RegularNodeGlobalIds, //input/ ouput + this->AugmentedTree->DataValues, // input/ouput + this->AugmentedTree->Regular2Supernode, // input/ouput + this->AugmentedTree->Superparents // input/ouput + ); + } + + // We have one last bit of cleanup to do. If there were attachment points, then the round in which they transfer has been removed + // While it is possible to turn this into a null round, it is better to reduce the iteration count by one and resize the arrays + // To do this, we access the *LAST* element written and check to see whether it is in the final iteration (according to the base tree) + // But there might be *NO* supernodes in the round, so we check first + vtkm::Id iterationArraySize = + vtkm::cont::ArrayGetValue(roundNumber, this->AugmentedTree->NumIterations); + if (iterationArraySize > 0) + { // at least one iteration + vtkm::Id lastSupernodeThisLevel = this->AugmentedTree->Supernodes.GetNumberOfValues() - 1; + vtkm::Id lastIterationThisLevel = vtkm::worklet::contourtree_augmented::MaskedIndex( + vtkm::cont::ArrayGetValue(lastSupernodeThisLevel, this->AugmentedTree->WhichIteration)); + // if there were no attachment points, it will be in the last iteration: if there were attachment points, it will be in the previous one + if (lastIterationThisLevel < iterationArraySize - 1) + { // attachment point round was removed + // decrement the iteration count (still with an extra element as sentinel) + this->AugmentedTree->NumIterations.WritePortal(roundNumber, iterationArraySize - 1); + // shrink the supernode array + this->AugmentedTree->FirstSupernodePerIteration[roundNumber].Allocate( + iterationArraySize, vtkm::CopyFlag::On); // shrink array but keep values + this->AugmentedTree->FirstSupernodePerIteration[roundNumber].WritePortal().Set( + iterationArraySize - 1, this->AugmentedTree->Supernodes.GetNumberOfValues()); + // for the hypernode array, the last iteration is guaranteed not to have hyperarcs by construction + // so the last iteration will already have the correct sentinel value, and we just need to shrink the array + this->AugmentedTree->FirstHypernodePerIteration[roundNumber].Allocate( + iterationArraySize, vtkm::CopyFlag::On); // shrink array but keep values + } // attachment point round was removed + } // at least one iteration + + // in the interests of debug, we resize the sorting array to zero here, + // even though we will re-resize them in the next function + this->SupernodeSorter.ReleaseResources(); + this->GlobalRegularIDSet.ReleaseResources(); + this->DataValueSet.ReleaseResources(); + this->SuperparentSet.ReleaseResources(); + this->SupernodeIDSet.ReleaseResources(); +} // CreateSuperarcs() + + +// debug routine +template +std::string HierarchicalAugmenter::DebugPrint(std::string message, + const char* fileName, + long lineNum) +{ // 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 << "Block " << std::setw(4) << this->BlockID << ": " << std::left << message + << std::endl; + resultStream << "----------------------------------------" << std::endl; + + resultStream << this->BaseTree->DebugPrint( + (message + std::string(" Base Tree")).c_str(), fileName, lineNum); + resultStream << this->AugmentedTree->DebugPrint( + (message + std::string(" Augmented Tree")).c_str(), fileName, lineNum); + resultStream << "========================================" << std::endl; + resultStream << "Local List of Attachment Points" << std::endl; + vtkm::worklet::contourtree_augmented::PrintHeader(this->GlobalRegularIds.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Global Regular Ids", this->GlobalRegularIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintValues( + "Data Values", this->DataValues, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Supernode Ids", this->SupernodeIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Superparents", this->Superparents, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Superparent Rounds", this->SuperparentRounds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "WhichRounds", this->WhichRounds, -1, resultStream); + resultStream << std::endl; + resultStream << "Outgoing Attachment Points" << std::endl; + vtkm::worklet::contourtree_augmented::PrintHeader(this->OutGlobalRegularIds.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Out Global Regular Ids", this->OutGlobalRegularIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintValues( + "Out Data Values", this->OutDataValues, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Out Supernode Ids", this->OutSupernodeIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Out Superparents", this->OutSuperparents, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Out Superparent Rounds", this->OutSuperparentRounds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Out WhichRounds", this->OutWhichRounds, -1, resultStream); + resultStream << std::endl; + resultStream << "Holding Arrays" << std::endl; + vtkm::worklet::contourtree_augmented::PrintHeader( + this->FirstAttachmentPointInRound.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "First Attach / Rd", this->FirstAttachmentPointInRound, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintHeader(this->AttachmentIds.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "AttachmentIds", this->AttachmentIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintHeader(this->NewSupernodeIds.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "New Supernode Ids", this->NewSupernodeIds, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintHeader(this->KeptSupernodes.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Kept Supernodes", this->KeptSupernodes, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintHeader(this->SupernodeSorter.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Supernode Sorter", this->SupernodeSorter, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Global Regular Id", this->GlobalRegularIdSet, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintValues( + "Data Values", this->DataValueSet, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Superparents", this->SuperparentSet, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "SupernodeIds", this->SupernodeIdSet, -1, resultStream); + resultStream << std::endl; + resultStream << std::endl; + + vtkm::worklet::contourtree_augmented::PrintHeader(this->SupernodeSorter.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Supernode Id", this->SupernodeSorter, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Permuted Superparent", + vtkm::cont::make_ArrayHandlePermutation(this->SupernodeSorter, this->SuperparentSet), + -1, + resultStream); + vtkm::worklet::contourtree_augmented::PrintValues( + "Permuted Value", + vtkm::cont::make_ArrayHandlePermutation(this->SupernodeSorter, this->DataValueSet), + -1, + resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Permuted Global Id", + vtkm::cont::make_ArrayHandlePermutation(this->SupernodeSorter, this->GlobalRegularIdSet), + -1, + resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "Permuted Supernode Id", + vtkm::cont::make_ArrayHandlePermutation(this->SupernodeSorter, this->SupernodeIdSet), + -1, + resultStream); + resultStream << std::endl; + resultStream << std::endl; + + vtkm::worklet::contourtree_augmented::PrintHeader(this->RegularSuperparents.GetNumberOfValues()); + vtkm::worklet::contourtree_augmented::PrintIndices( + "RegularNodesNeeded", this->RegularNodesNeeded, -1, resultStream); + vtkm::worklet::contourtree_augmented::PrintIndices( + "RegularSuperparents", this->RegularSuperparents, -1, resultStream); + resultStream << std::endl; + // for now, nothing here at all + //std::string hierarchicalTreeDotString = HierarchicalContourTreeDotGraphPrint(message, + // this->BaseTree, + // SHOW_SUPER_STRUCTURE|SHOW_HYPER_STRUCTURE|GV_NODE_NAME_USES_GLOBAL_ID|SHOW_ALL_IDS|SHOW_ALL_SUPERIDS|SHOW_ALL_HYPERIDS|SHOW_EXTRA_DATA, + // this->BlockId, + // this->SweepValues + // ); + return resultStream.str(); +} // DebugPrint() + + + + +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h b/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h index 902546cc8..bde562c3d 100644 --- a/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h +++ b/vtkm/worklet/contourtree_distributed/HierarchicalHyperSweeper.h @@ -683,6 +683,7 @@ std::string HierarchicalHyperSweeper::DebugPrint(std::strin "Sorted Transfer", this->SortedTransferTarget - 1, resultStream); vtkm::worklet::contourtree_augmented::PrintIndices( "Sort Permute", this->SuperSortPermute - 1, resultStream); + return resultStream.str(); } // DebugPrint() diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentAndSupernodeComparator.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentAndSupernodeComparator.h new file mode 100644 index 000000000..d23aa8aa1 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentAndSupernodeComparator.h @@ -0,0 +1,202 @@ +//============================================================================ +// 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. +// +//============================================================================= +// +// COMMENTS: +// +// A comparator that sorts supernode pairs by: +// 1. the superparent (ie the superarc into which an attachment point inserts) +// note that this implicitly sorts on round of insertion as well +// 2. data value +// 3. global regular ID +// +// The superparent is assumed to have a flag indicating ascending/descending, and this +// needs to be used to get the correct inwards ordering along each superarc +// +//======================================================================================= + + +#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_hyper_augmenter_attachment_and_supernode_comparator_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_augmenter_attachment_and_supernode_comparator_h + +#include +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + + +/// Compartor implementation used in HierarchicalAugmenter::ResizeArrays to sort this->SupernodeSorter +/// A comparator that sorts supernode pairs by: +/// 1. the superparent (ie the superarc into which an attachment point inserts) +/// note that this implicitly sorts on round of insertion as well +/// 2. data value +/// 3. global regular ID +/// +/// The superparent is assumed to have a flag indicating ascending/descending, and this +/// needs to be used to get the correct inwards ordering along each superarc +template +class AttachmentAndSupernodeComparatorImpl +{ +public: + using IdArrayPortalType = + typename vtkm::worklet::contourtree_augmented::IdArrayType::ReadPortalType; + using FieldArrayPortalType = typename FieldArrayType::ReadPortalType; + + // constructor + VTKM_CONT + AttachmentAndSupernodeComparatorImpl(IdArrayPortalType superparentSetPortal, + IdArrayPortalType dataValueSetPortal, + IdArrayPortalType globalRegularIdSetPortal) + : SuperparentSetPortal(superparentSetPortal) + , DataValueSetPortal(dataValueSetPortal) + , GlobalRegularIdSetPortal(globalRegularIdSetPortal) + { // constructor + } // constructor + + // () operator - gets called to do comparison + VTKM_EXEC + bool operator()(const vtkm::Id& left, const vtkm::Id& right) const + { // operator() + // first comparison is on superparent WITHOUT ascending descending flag + if (vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentSetPortal.Get(left)) < + vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentSetPortal.Get(right))) + { + return true; + } + if (vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentSetPortal.Get(left)) > + vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentSetPortal.Get(right))) + { + return false; + } + + // second comparison is on data value + if (this->DataValueSetPortal.Get(left) < this->DataValueSetPortal.Get(right)) + { + return vtkm::worklet::contourtree_augmented::IsAscending( + this->SuperparentSetPortal.Get(left)); + } + if (this->DataValueSetPortal.Get(left) > this->DataValueSetPortal.Get(right)) + { + return !vtkm::worklet::contourtree_augmented::IsAscending( + this->SuperparentSetPortal.Get(left)); + } + + // third comparison is on global regular ID + if (this->GlobalRegularIdSetPortal.Get(left) < this->GlobalRegularIdSetPortal.Get(right)) + { + return vtkm::worklet::contourtree_augmented::IsAscending( + this->SuperparentSetPortal.Get(left)); + } + if (this->GlobalRegularIdSetPortal.Get(left) > this->GlobalRegularIdSetPortal.Get(right)) + { + return !vtkm::worklet::contourtree_augmented::IsAscending( + this->SuperparentSetPortal.Get(left)); + } + + // fall-through (should never happen) + return false; + } // operator() + +private: + IdArrayPortalType SuperparentSetPortal; + FieldArrayPortalType DataValueSetPortal; + IdArrayPortalType GlobalRegularIdSetPortal; +}; // AttachmentAndSupernodeComparatorImpl + + +/// Execution object for Compartor used in HierarchicalAugmenter::ResizeArrays to sort this->SupernodeSorter +/// A comparator that sorts supernode pairs by: +/// 1. the superparent (ie the superarc into which an attachment point inserts) +/// note that this implicitly sorts on round of insertion as well +/// 2. data value +/// 3. global regular ID +/// +/// The superparent is assumed to have a flag indicating ascending/descending, and this +/// needs to be used to get the correct inwards ordering along each superarc +template +class AttachmentAndSupernodeComparator : public vtkm::cont::ExecutionObjectBase +{ +public: + // constructor - takes vectors as parameters + VTKM_CONT + AttachmentAndSupernodeComparator( + const vtkm::worklet::contourtree_augmented::IdArrayType superparentSet, + const vtkm::worklet::contourtree_augmented::IdArrayType dataValueSet, + const vtkm::worklet::contourtree_augmented::IdArrayType globalRegularIdSet) + : SuperparentSet(superparentSet) + , DataValueSet(dataValueSet) + , GlobalRegularIdSet(globalRegularIdSet) + { // constructor + } // constructor + + /// Create a AttachmentAndSupernodeComparatorImpl object for use in the sort or worklet + VTKM_CONT AttachmentAndSupernodeComparatorImpl PrepareForExecution( + vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) const + { + return AttachmentAndSupernodeComparatorImpl( + this->SuperparentSet.PrepareForInput(device, token), + this->DataValueSet.PrepareForInput(device, token), + this->GlobalRegularIdSet.PrepareForInput(device, token)); + } + +private: + /// the superparent Id + vtkm::worklet::contourtree_augmented::IdArrayType SuperparentSet; + /// the global rergular Id for tiebreak + FieldArrayType DataValueSet; + /// the supernode Id for tiebreak + vtkm::worklet::contourtree_augmented::IdArrayType GlobalRegularIdSet; +}; // AttachmentAndSupernodeComparator + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentSuperparentAndIndexComparator.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentSuperparentAndIndexComparator.h new file mode 100644 index 000000000..7fd0f8285 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/AttachmentSuperparentAndIndexComparator.h @@ -0,0 +1,187 @@ +//============================================================================ +// 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. +// +//============================================================================= +// +// COMMENTS: +// +// A comparator that sorts supernode pairs by: +// 1. the superparent round +// 2. global regular Id +// 3. supernode Id (if any) +// +// We don't care about the orientation of the superarc for this comparator +// +// For duplicates, we assume that at MOST one (in fact, it should always be EXACTLY one) +// copy has a supernode Id set. This is because when we exchange between blocks, we set +// the supernode Id to NO_SUCH_ELEMENT. That way, only the copy that belongs on the block +// has the supernode Id set. We want to ensure that it appears at the beginning of the segment, +// and don't care about the ordering of any others. +// +//======================================================================================= + + +#ifndef vtk_m_worklet_contourtree_distributed_hierarchical_hyper_augmenter_attachment_superparent_and_index_comparator_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_augmenter_attachment_superparent_and_index_comparator_h + +#include +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + + +/// Implementation for a comparator that sorts supernode pairs by: +/// 1. the superparent round +/// 2. global regular Id +/// 3. supernode Id (if any) +class AttachmentSuperparentAndIndexComparatorImpl +{ +public: + using IdArrayPortalType = + typename vtkm::worklet::contourtree_augmented::IdArrayType::ReadPortalType; + + // constructor + VTKM_CONT + AttachmentSuperparentAndIndexComparatorImpl(IdArrayPortalType superparentsPortal, + IdArrayPortalType globalRegularIdsPortal, + IdArrayPortalType supernodeIdsPortal) + : SuperparentsPortal(superparentsPortal) + , GlobalRegularIdsPortal(globalRegularIdsPortal) + , SupernodeIdsPortal(supernodeIdsPortal) + { // constructor + } // constructor + + // () operator - gets called to do comparison + VTKM_EXEC + bool operator()(const vtkm::Id& left, const vtkm::Id& right) const + { // operator() + // first comparison is on superparent WITHOUT ascending descending flag + if (vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentsPortal.Get(left)) < + vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentsPortal.Get(right))) + { + return true; + } + if (vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentsPortal.Get(left)) > + vtkm::worklet::contourtree_augmented::MaskedIndex(this->SuperparentsPortal.Get(right))) + { + return false; + } + // second comparison is on global regular Id + if (this->GlobalRegularIdsPortal.Get(left) < this->GlobalRegularIdsPortal.Get(right)) + { + return vtkm::worklet::contourtree_augmented::IsAscending(this->SuperparentsPortal.Get(left)); + } + if (this->GlobalRegularIdsPortal.Get(left) > this->GlobalRegularIdsPortal.Get(right)) + { + return !vtkm::worklet::contourtree_augmented::IsAscending(this->SuperparentsPortal.Get(left)); + } + // third comparison is on supernode Ids + if (!vtkm::worklet::contourtree_augmented::NoSuchElement(this->SupernodeIdsPortal.Get(left))) + { + return true; + } + else if (!vtkm::worklet::contourtree_augmented::NoSuchElement( + this->SupernodeIdsPortal.Get(right))) + { + return false; + } + // in this case, both were NSE, so sort on the index values + return (left < right); + + } // operator() + +private: + IdArrayPortalType SuperparentsPortal; + IdArrayPortalType GlobalRegularIdsPortal; + IdArrayPortalType SupernodeIdsPortal; +}; // AttachmentSuperparentAndIndexComparatorImpl + + +/// Execution object for a comparator that sorts supernode pairs by: +/// 1. the superparent round +/// 2. global regular Id +/// 3. supernode Id (if any) +class AttachmentSuperparentAndIndexComparator : public vtkm::cont::ExecutionObjectBase +{ +public: + // constructor - takes vectors as parameters + VTKM_CONT + AttachmentSuperparentAndIndexComparator( + const vtkm::worklet::contourtree_augmented::IdArrayType superparents, + const vtkm::worklet::contourtree_augmented::IdArrayType globalRegularIds, + const vtkm::worklet::contourtree_augmented::IdArrayType supernodeIds) + : Superparents(superparents) + , GlobalRegularIds(globalRegularIds) + , SupernodeIds(supernodeIds) + { // constructor + } // constructor + + /// Create a AttachmentSuperparentAndIndexComparatorImpl object for use in the sort or worklet + VTKM_CONT AttachmentSuperparentAndIndexComparatorImpl + PrepareForExecution(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const + { + return AttachmentSuperparentAndIndexComparatorImpl( + this->Superparents.PrepareForInput(device, token), + this->GlobalRegularIds.PrepareForInput(device, token), + this->SupernodeIds.PrepareForInput(device, token)); + } + +private: + /// the superparent Id + vtkm::worklet::contourtree_augmented::IdArrayType Superparents; + /// the global rergular Id for tiebreak + vtkm::worklet::contourtree_augmented::IdArrayType GlobalRegularIds; + /// the supernode Id for tiebreak + vtkm::worklet::contourtree_augmented::IdArrayType SupernodeIds; +}; // AttachmentSuperparentAndIndexComparator + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CMakeLists.txt b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CMakeLists.txt new file mode 100644 index 000000000..a302f8cc6 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CMakeLists.txt @@ -0,0 +1,28 @@ +##============================================================================ +## 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 + IsAttachementPointPredicate.h + IsAscendingDecorator.h + IsAttachementPointNeededPredicate.h + AttachmentSuperparentAndIndexComparator.h + SetFirstAttachmentPointInRoundWorklet.h + UpdateHyperstructureSetHyperarcsAndNodesWorklet.h + UpdateHyperstructureSetSuperchildrenWorklet.h + FindSuperparentForNecessaryNodesWorklet.h + CopyBaseRegularStructureWorklet.h + NotNoSuchElementPredicate.h + SetSuperparentSetDecorator.h + AttachmentAndSupernodeComparator.h + ResizeArraysBuildNewSupernodeIdsWorklet.h + CreateSuperarcsWorklet.h +) + +vtkm_declare_headers(${headers}) diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CopyBaseRegularStructureWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CopyBaseRegularStructureWorklet.h new file mode 100644 index 000000000..11c3ecbf7 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CopyBaseRegularStructureWorklet.h @@ -0,0 +1,166 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_copy_base_regular_structure_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_copy_base_regular_structure_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalAugmenter::CopyBaseRegularStructure for +/// finding the superparent for each node needed +class CopyBaseRegularStructureWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + /// NOTE: We require the input arrays (aside form the input domain) to be permutted by the + /// regularNodesNeeded input domain so that we can use FieldIn instead of WholeArrayIn + /// NOTE: We require ArrayHandleView for the output arrays of the range [numExistingRegular:end] so + /// that we can use FieldOut instead of requiring WholeArrayInOut + using ControlSignature = void( + FieldIn + regularNodesNeededRange, // input domain ArrayHandleIndex of [0, regularNodesNeeded.GetNumberOfValues()] + FieldIn + baseTreeRegularNodeGlobalIdsPermuted, // input baseTree->regularNodeGlobalIds permuted by regularNodesNeeded + FieldIn baseTreeDataValuesPermuted, // input baseTree->dataValues permuted by regularNodesNeeded + FieldIn regularSuperparentsPermuted, // input regularSuperparents permuted by regularNodesNeeded + FieldOut + augmentedTreeRegularNodeGlobalIdsView, // output view of augmentedTree->regularNodeGlobalIds[numExistingRegular:] + FieldOut + augmentedTreeDataValuesView, // output view of augmentedTree->dataValues[numExistingRegular:] + FieldOut + augmentedTreeSuperparentsView, // output view of augmentedTree->superparents[numExistingRegular:] + FieldOut + augmentedTreeRegularNodeSortOrderView // output view of augmentedTree->regularNodeSortOrder[numExistingRegular:] + ); + using ExecutionSignature = void(_1, _2, _3, _4, _5, _6, _7, _8); + using InputDomain = _1; + + /// Default Constructor + VTKM_EXEC_CONT + CopyBaseRegularStructureWorklet(const vtkm::Id& numExistingRegular) + : NumExistingRegular(numExistingRegular) + { + } + + /// operator() of the workelt + template + VTKM_EXEC void operator()( + const vtkm::Id& neededRegNode, // InputIndex in [0, regularNodesNeeded.GetNumberOfValues()] + const vtkm::Id& + baseTreeRegularNodeGlobalId, // same as baseTree->regularNodeGlobalIds[oldRegularID] + const FieldType& baseTreeDataValue, // same as baseTree->dataValues[oldRegularID] + const vtkm::Id& regularSuperparentsValue, // same regularSuperparents[oldRegularID] + vtkm::Id& + augmentedTreeRegularNodeGlobalIdValue, // same as augmentedTree->regularNodeGlobalIDs[NumExistingRegular + neededRegNode] = ... + FieldType& + augmentedTreeDataValue, // same as augmentedTree->dataValues[NumExistingRegular + neededRegNode] = ... + vtkm::Id& + augmentedTreeSuperparentsValue, // same as augmentedTree->superparents[NumExistingRegular + neededRegNode] = ... + vtkm::Id& + augmentedTreeRegularNodeSortOrderValue // same as augmentedTree->regularNodeSortOrder [NumExistingRegular + neededRegNode] = ... + ) const + { + // per regular node needing addition + // retrieve the existing index. oldRegularID is set on input + vtkm::Id newRegularId = this->NumExistingRegular + + neededRegNode; // not needed since we do ArrayHandleViews on the outside + + // now use them to copy data + augmentedTreeRegularNodeGlobalIdValue = baseTreeRegularNodeGlobalId; + augmentedTreeDataValue = baseTreeDataValue; + augmentedTreeSuperparentsValue = regularSuperparentsValue; + + // this one is special since we need to resort - set it to identity, leaving the sort order of old vertices alone + // this *MAY* make certain sorts run faster + augmentedTreeRegularNodeSortOrderValue = newRegularId; + + // NOTE: we can skip this step since Regular2supernode is already initalized with NO_SUCH_ELEMENT + // since these are *ALL* only regular nodes, this one's easy: + // augmentedTree->regular2supernode [newRegularID] = NO_SUCH_ELEMENT; + + // In serial this worklet implements the following operation + /* + for (vtkm::Id neededRegNode = 0; neededRegNode < nRegNeeded; neededRegNode++) + { // per regular node needing addition + // retrieve the existing index + vtkm::Id oldRegularID = regularNodesNeeded[neededRegNode]; + // and compute the new index + vtkm::Id newRegularID = nExistingRegular + neededRegNode; + + // now use them to copy data + augmentedTree->regularNodeGlobalIDs [newRegularID] = baseTree->regularNodeGlobalIDs [oldRegularID]; + augmentedTree->dataValues [newRegularID] = baseTree->dataValues [oldRegularID]; + augmentedTree->superparents [newRegularID] = regularSuperparents [oldRegularID]; + + // this one is special since we need to resort - set it to identity, leaving the sort order of old vertices alone + // this *MAY* make certain sorts run faster + augmentedTree->regularNodeSortOrder [newRegularID] = newRegularID; + + // since these are *ALL* only regular nodes, this one's easy: + augmentedTree->regular2supernode [newRegularID] = NO_SUCH_ELEMENT; + } // per regular node needing addition + */ + } // operator()() +private: + const vtkm::Id NumExistingRegular; + +}; // CopyBaseRegularStructureWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CreateSuperarcsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CreateSuperarcsWorklet.h new file mode 100644 index 000000000..cfaea8685 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/CreateSuperarcsWorklet.h @@ -0,0 +1,445 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_create_superarcs_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_create_superarcs_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used to implement the main part of HierarchicalAugmenter::CreateSuperarcs +/// Connect superarcs for the level & set hyperparents & superchildren count, whichRound, +/// whichIteration, super2hypernode +class CreateSuperarcsWorklet : public vtkm::worklet::WorkletMapField +{ +public: + // VTKm only defines 20 placeholders for the execution signature, but we need a few more here + using _21 = vtkm::placeholders::Arg<21>; + using _22 = vtkm::placeholders::Arg<22>; + using _23 = vtkm::placeholders::Arg<23>; + + // TODO: This worklet could probably be optimized further to reduce the use of WholeArray passing + /// Control signature for the worklet + using ControlSignature = void( + WholeArrayIn supernodeSorter, // input domain (we need access to InputIndex and InputIndex+1) + WholeArrayIn superparentSet, // input + WholeArrayIn baseTreeSuperarcs, // input + WholeArrayIn newSupernodeIds, // input + WholeArrayIn + baseTreeHyperparents, // input TODO: could potentially be a FieldIn with some array shuffle magic + WholeArrayIn + baseTreeSupernodes, // input TODO: could potentially be a FieldIn with some array shuffle magic + WholeArrayIn + baseTreeRegularNodeGlobalIds, // input TODO: could potentially be a FieldIn with some array shuffle magic + WholeArrayIn + globalRegularIdSet, // input TODO: could potentially be a FieldIn with some array shuffle magic + WholeArrayIn baseTreeSuper2Hypernode, // input TODO: FieldIn possible with array shuffle? + WholeArrayIn baseTreeWhichRound, // input TODO: FieldIn possible with array shuffle? + WholeArrayIn baseTreeWhichIteration, // input TODO: FieldIn possible with array shuffle? + WholeArrayIn dataValueSet, // input TODO: FieldIn possible with array shuffle? + FieldOut + augmentedTreeSuperarcsView, // output view of ArrayHandleView(this->AugmentedTree->Superarcs[, this->NumSupernodesAlready, this->SupernodeSorter.GetNumberOfValues()) + WholeArrayInOut augmentedTreeHyperparents, // input/output + WholeArrayInOut + augmentedTreeFirstSupernodePerIteration, // input/output augmentedTree->firstSupernodePerIteration[roundNumber] + WholeArrayInOut + augmentedTreeSupernodes, // input/output TODO: Could potentially change to FieldIn/FieldInOut when permutting the array + WholeArrayInOut + augmentedTreeSuper2hypernode, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeWhichRound, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeWhichIteration, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeRegularNodeGlobalIds, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeDataValues, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeRegular2Supernode, // input/ouput TODO: Is FieldOut possible with array shuffle? + WholeArrayInOut + augmentedTreeSuperparents // input/ouput TODO: Is FieldOut possible with array shuffle? + ); + using ExecutionSignature = void(InputIndex, + _1, + _2, + _3, + _4, + _5, + _6, + _7, + _8, + _9, + _10, + _11, + _12, + _13, + _14, + _15, + _16, + _17, + _18, + _19, + _20, + _21, + _22, + _23); + using InputDomain = _1; + + /// Default Constructor + VTKM_EXEC_CONT + CreateSuperarcsWorklet( + const vtkm::Id& numSupernodesAlready, + const vtkm::Id& baseTreeNumRounds, + const vtkm::Id& + augmentedTreeNumIterations, // set to vtkm::cont::ArrayGetValue(roundNumber, this->AugmentedTree->NumIterations) + const vtkm::Id& roundNumber) + : NumSupernodesAlready(numSupernodesAlready) + , BaseTreeNumRounds(baseTreeNumRounds) + , AugmentedTreeNumIterations(augmentedTreeNumIterations) + , RoundNumber(roundNumber) + + { + } + + /// operator() of the workelt + template + VTKM_EXEC void operator()( + const vtkm::Id& supernode, // InputIndex of supernodeSorter + const InFieldPortalType& supernodeSorterPortal, + const InFieldPortalType& superparentSetPortal, + const InFieldPortalType& baseTreeSuperarcsPortal, + const InFieldPortalType& newSupernodeIdsPortal, + const InFieldPortalType& baseTreeHyperparentsPortal, + const InFieldPortalType& baseTreeSupernodesPortal, + const InFieldPortalType& baseTreeRegularNodeGlobalIdsPortal, + const InFieldPortalType& globalRegularIdSetPortal, + const InFieldPortalType& baseTreeSuper2hypernodePortal, + const InFieldPortalType& baseTreeWhichRoundPortal, + const InFieldPortalType& baseTreeWhichIterationPortal, + const InFieldPortalType2& dataValueSetPortal, + vtkm::Id& augmentedTreeSuperarcsValue, // same as augmentedTree->superarcs[newSupernodeId] + const InOutFieldPortalType& augmentedTreeHyperparentsPortal, + const InOutFieldPortalType& + augmentedTreeFirstSupernodePerIterationPortal, // augmentedTree->firstSupernodePerIteration[roundNumber] + const InOutFieldPortalType& augmentedTreeSupernodesPortal, + const InOutFieldPortalType& augmentedTreeSuper2hypernodePortal, + const InOutFieldPortalType& augmentedTreeWhichRoundPortal, + const InOutFieldPortalType& augmentedTreeWhichIterationPortal, + const InOutFieldPortalType& augmentedTreeRegularNodeGlobalIdsPortal, + const InOutFieldPortalType2& augmentedTreeDataValuesPortal, + const InOutFieldPortalType& augmentedTreeRegular2SupernodePortal, + const InOutFieldPortalType& augmentedTreeSuperparentsPortal) const + { + // per supernode in the set + // retrieve the index from the sorting index array + vtkm::Id supernodeSetIndex = supernodeSorterPortal.Get(supernode); + + // work out the new supernode Id + vtkm::Id newSupernodeId = this->NumSupernodesAlready + supernode; + + // At all levels above 0, we used to keep regular vertices in case + // they are attachment points. After augmentation, we don't need to. + // Instead, at all levels above 0, the regular nodes in each round + // are identical to the supernodes. In order to avoid confusion, + // we will copy the Id into a separate variable + vtkm::Id newRegularId = newSupernodeId; + + // setting the supernode's regular Id is now trivial + augmentedTreeSupernodesPortal.Set(newSupernodeId, newRegularId); + + // retrieve the ascending flag from the superparent + vtkm::Id superparentSetVal = superparentSetPortal.Get(supernodeSetIndex); + bool superarcAscends = vtkm::worklet::contourtree_augmented::IsAscending(superparentSetVal); + + // strip the ascending flag from the superparent + vtkm::Id superparentOldSuperId = + vtkm::worklet::contourtree_augmented::MaskedIndex(superparentSetVal); + + // setting the superarc is done the usual way. Our sort routine has ended up + // with the supernodes arranged in either ascending or descending order + // inwards along the parent superarc (as expressed by the superparent Id). + // Each superarc except the last in the segment points to the next one: + // the last one points to the target of the original superarc. + // first test to see if we're the last in the array + if (supernode == supernodeSorterPortal.GetNumberOfValues() - 1) + { // last in the array + // special case for root of entire tree at end of top level + if (RoundNumber == this->BaseTreeNumRounds) + { + augmentedTreeSuperarcsValue = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT; + } + else + { // not the tree root + // retrieve the target of the superarc from the base tree (masking to strip out the ascending flag) + vtkm::Id oldTargetSuperId = vtkm::worklet::contourtree_augmented::MaskedIndex( + baseTreeSuperarcsPortal.Get(superparentOldSuperId)); + // convert to a new supernode Id + vtkm::Id newTargetSuperId = newSupernodeIdsPortal.Get(oldTargetSuperId); + // add the ascending flag back in and store in the array + augmentedTreeSuperarcsValue = newTargetSuperId | + (superarcAscends ? vtkm::worklet::contourtree_augmented::IS_ASCENDING : 0x00); + } // not the tree root + // since there's an extra entry in the firstSupernode array as a sentinel, set it + augmentedTreeFirstSupernodePerIterationPortal.Set( + this->AugmentedTreeNumIterations, augmentedTreeSupernodesPortal.GetNumberOfValues()); + } // last in the array + else if (superparentOldSuperId != + vtkm::worklet::contourtree_augmented::MaskedIndex( + superparentSetPortal.Get(supernodeSorterPortal.Get(supernode + 1)))) + { // last in the segment + // retrieve the target of the superarc from the base tree (masking to strip out the ascending flag) + vtkm::Id oldTargetSuperId = vtkm::worklet::contourtree_augmented::MaskedIndex( + baseTreeSuperarcsPortal.Get(superparentOldSuperId)); + // convert to a new supernode Id + vtkm::Id newTargetSuperId = newSupernodeIdsPortal.Get(oldTargetSuperId); + // add the ascending flag back in and store in the array + augmentedTreeSuperarcsValue = newTargetSuperId | + (superarcAscends ? vtkm::worklet::contourtree_augmented::IS_ASCENDING : 0x00); + + // since we're the last in the segment, we check to see if we are at the end of an iteration + vtkm::Id iterationNumber = vtkm::worklet::contourtree_augmented::MaskedIndex( + baseTreeWhichIterationPortal.Get(superparentOldSuperId)); + vtkm::Id iterationNumberOfNext = vtkm::worklet::contourtree_augmented::MaskedIndex( + baseTreeWhichIterationPortal.Get(superparentOldSuperId + 1)); + + if (iterationNumber != iterationNumberOfNext) + { // boundary of iterations + // If so, we set the "firstSupernodePerIteration" for the next + augmentedTreeFirstSupernodePerIterationPortal.Set(iterationNumberOfNext, + newSupernodeId + 1); + } // boundary of iterations + } // last in the segment + else + { // not last in the segment + // the target is always the next one, so just store it with the ascending flag + augmentedTreeSuperarcsValue = (newSupernodeId + 1) | + (superarcAscends ? vtkm::worklet::contourtree_augmented::IS_ASCENDING : 0x00); + } // not last in the segment + + // set the first supernode in the first iteration to the beginning of the round + augmentedTreeFirstSupernodePerIterationPortal.Set(0, this->NumSupernodesAlready); + + // setting the hyperparent is straightforward since the hyperstructure is preserved + // we take the superparent (which is guaranteed to be in the baseTree), find it's hyperparent and use that + augmentedTreeHyperparentsPortal.Set(newSupernodeId, + baseTreeHyperparentsPortal.Get(superparentOldSuperId)); + + // similarly, the super2hypernode should carry over, but it's harder to test because of the attachment points which + // do not have valid old supernode Ids. Instead, we check their superparent's regular global Id against them: if it + // matches, then it must be the start of the superarc, in which case it does have an old Id, and we can then use the + // existing hypernode Id + vtkm::Id superparentOldRegularId = baseTreeSupernodesPortal.Get(superparentOldSuperId); + vtkm::Id superparentGlobalId = baseTreeRegularNodeGlobalIdsPortal.Get(superparentOldRegularId); + if (superparentGlobalId == globalRegularIdSetPortal.Get(supernodeSetIndex)) + { + augmentedTreeSuper2hypernodePortal.Set( + newSupernodeId, baseTreeSuper2hypernodePortal.Get(superparentOldSuperId)); + } + else + { + augmentedTreeSuper2hypernodePortal.Set(newSupernodeId, + vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT); + } + + // which round and iteration carry over + augmentedTreeWhichRoundPortal.Set(newSupernodeId, + baseTreeWhichRoundPortal.Get(superparentOldSuperId)); + augmentedTreeWhichIterationPortal.Set(newSupernodeId, + baseTreeWhichIterationPortal.Get(superparentOldSuperId)); + + // now we deal with the regular-sized arrays + + // copy the global regular Id and data value + augmentedTreeRegularNodeGlobalIdsPortal.Set(newRegularId, + globalRegularIdSetPortal.Get(supernodeSetIndex)); + augmentedTreeDataValuesPortal.Set(newRegularId, dataValueSetPortal.Get(supernodeSetIndex)); + + // the sort order will be dealt with later + // since all of these nodes are supernodes, they will be their own superparent, which means that: + // a. the regular2node can be set immediately + augmentedTreeRegular2SupernodePortal.Set(newRegularId, newSupernodeId); + // b. as can the superparent + augmentedTreeSuperparentsPortal.Set(newRegularId, newSupernodeId); + + // In serial this worklet implements the following operation + /* + for (vtkm::Id supernode = 0; supernode < supernodeSorter.size(); supernode++) + { // per supernode in the set + // retrieve the index from the sorting index array + vtkm::Id supernodeSetIndex = supernodeSorter[supernode]; + + // work out the new supernode ID + vtkm::Id newSupernodeID = numSupernodesAlready + supernode; + + // At all levels above 0, we used to keep regular vertices in case they are attachment points. After augmentation, we don't need to. + // Instead, at all levels above 0, the regular nodes in each round are identical to the supernodes + // In order to avoid confusion, we will copy the ID into a separate variable + vtkm::Id newRegularID = newSupernodeID; + + // setting the supernode's regular ID is now trivial + augmentedTree->supernodes [newSupernodeID] = newRegularID; + + // retrieve the ascending flag from the superparent + bool superarcAscends = isAscending(superparentSet[supernodeSetIndex]); + + // strip the ascending flag from the superparent + vtkm::Id superparentOldSuperID = maskedIndex(superparentSet[supernodeSetIndex]); + + // setting the superarc is done the usual way. Our sort routine has ended up with the supernodes arranged in either ascending or descending order + // inwards along the parent superarc (as expressed by the superparent ID). Each superarc except the last in the segment points to the next one: + // the last one points to the target of the original superarc. + // first test to see if we're the last in the array + if (supernode == supernodeSorter.size() - 1) + { // last in the array + // special case for root of entire tree at end of top level + if (roundNumber == baseTree->nRounds) + { + augmentedTree->superarcs[newSupernodeID] = NO_SUCH_ELEMENT; + } + else + { // not the tree root + // retrieve the target of the superarc from the base tree (masking to strip out the ascending flag) + vtkm::Id oldTargetSuperID = maskedIndex(baseTree->superarcs[superparentOldSuperID]); + // convert to a new supernode ID + vtkm::Id newTargetSuperID = newSupernodeIDs[oldTargetSuperID]; + // add the ascending flag back in and store in the array + augmentedTree->superarcs[newSupernodeID] = newTargetSuperID | (superarcAscends ? IS_ASCENDING : 0x00); + } // not the tree root + // since there's an extra entry in the firstSupernode array as a sentinel, set it + augmentedTree->firstSupernodePerIteration[roundNumber][augmentedTree->nIterations[roundNumber]] = augmentedTree->supernodes.size(); + } // last in the array + else if (superparentOldSuperID != maskedIndex(superparentSet[supernodeSorter[supernode+1]])) + { // last in the segment + // retrieve the target of the superarc from the base tree (masking to strip out the ascending flag) + vtkm::Id oldTargetSuperID = maskedIndex(baseTree->superarcs[superparentOldSuperID]); + // convert to a new supernode ID + vtkm::Id newTargetSuperID = newSupernodeIDs[oldTargetSuperID]; + // add the ascending flag back in and store in the array + augmentedTree->superarcs[newSupernodeID] = newTargetSuperID | (superarcAscends ? IS_ASCENDING : 0x00); + + // since we're the last in the segment, we check to see if we are at the end of an iteration + vtkm::Id iterationNumber = maskedIndex(baseTree->whichIteration[superparentOldSuperID]); + vtkm::Id iterationNumberOfNext = maskedIndex(baseTree->whichIteration[superparentOldSuperID + 1]); + + if (iterationNumber != iterationNumberOfNext) + { // boundary of iterations + // If so, we set the "firstSupernodePerIteration" for the next + augmentedTree->firstSupernodePerIteration[roundNumber][iterationNumberOfNext] = newSupernodeID + 1; + } // boundary of iterations + } // last in the segment + else + { // not last in the segment + // the target is always the next one, so just store it with the ascending flag + augmentedTree->superarcs[newSupernodeID] = (newSupernodeID+1) | (superarcAscends ? IS_ASCENDING : 0x00); + } // not last in the segment + + // set the first supernode in the first iteration to the beginning of the round + augmentedTree->firstSupernodePerIteration[roundNumber][0] = numSupernodesAlready; + + // setting the hyperparent is straightforward since the hyperstructure is preserved + // we take the superparent (which is guaranteed to be in the baseTree), find it's hyperparent and use that + augmentedTree->hyperparents [newSupernodeID] = baseTree->hyperparents [superparentOldSuperID]; + + // similarly, the super2hypernode should carry over, but it's harder to test because of the attachment points which + // do not have valid old supernode IDs. Instead, we check their superparent's regular global ID against them: if it + // matches, then it must be the start of the superarc, in which case it does have an old ID, and we can then use the + // existing hypernode ID + vtkm::Id superparentOldRegularID = baseTree->supernodes[superparentOldSuperID]; + vtkm::Id superparentGlobalID = baseTree->regularNodeGlobalIDs[superparentOldRegularID]; + if (superparentGlobalID == globalRegularIDSet[supernodeSetIndex]) + { + augmentedTree->super2hypernode [newSupernodeID] = baseTree->super2hypernode[superparentOldSuperID]; + } + else + { + augmentedTree->super2hypernode [newSupernodeID] = NO_SUCH_ELEMENT; + } + + // which round and iteration carry over + augmentedTree->whichRound [newSupernodeID] = baseTree->whichRound[superparentOldSuperID]; + augmentedTree->whichIteration [newSupernodeID] = baseTree->whichIteration[superparentOldSuperID]; + + // now we deal with the regular-sized arrays + + // copy the global regular ID and data value + augmentedTree->regularNodeGlobalIDs [newRegularID] = globalRegularIDSet[supernodeSetIndex]; + augmentedTree->dataValues [newRegularID] = dataValueSet[supernodeSetIndex]; + + // the sort order will be dealt with later + // since all of these nodes are supernodes, they will be their own superparent, which means that: + // a. the regular2node can be set immediately + augmentedTree->regular2supernode [newRegularID] = newSupernodeID; + // b. as can the superparent + augmentedTree->superparents [newRegularID] = newSupernodeID; + } // per supernode in the set + */ + } // operator()() + +private: + const vtkm::Id NumSupernodesAlready; + const vtkm::Id BaseTreeNumRounds; + const vtkm::Id AugmentedTreeNumIterations; + const vtkm::Id RoundNumber; + +}; // CreateSuperarcsWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/FindSuperparentForNecessaryNodesWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/FindSuperparentForNecessaryNodesWorklet.h new file mode 100644 index 000000000..ee4f8e59e --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/FindSuperparentForNecessaryNodesWorklet.h @@ -0,0 +1,210 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_find_superparent_for_necessary_nodes_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_find_superparent_for_necessary_nodes_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalAugmenter::CopyBaseRegularStructure for +/// finding the superparent for each node needed +class FindSuperparentForNecessaryNodesWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + using ControlSignature = void( + FieldIn baseTreeRegularNodeGlobalIds, // input domain + FieldIn baseTreeSuperparents, // input + FieldIn baseTreeDataValues, // input + WholeArrayIn baseTreeSuperarcs, // input + WholeArrayIn newSupernodeIds, // input + // Execution objects from the AugmentedTree to use the FindRegularByGlobal + // and FindSuperArcForUnknownNode for the hierarchical tree. + ExecObject findRegularByGlobal, + ExecObject findSuperArcForUnknownNode, + // Output arrays to populate + FieldOut regularSuperparents, // output + FieldOut regularNodesNeeded // output + ); + using ExecutionSignature = void(InputIndex, _1, _2, _3, _4, _5, _6, _7, _8, _9); + using InputDomain = _1; + + /// Default Constructor + VTKM_EXEC_CONT + FindSuperparentForNecessaryNodesWorklet() {} + + /// operator() of the workelt + template + VTKM_EXEC void operator()( + const vtkm::Id& regularNode, // InputIndex a.k.a out loop index + const vtkm::Id& globalRegularId, // same as baseTree->regularNodeGlobalIDs[regularNode]; + const vtkm::Id& oldSuperparent, // same as baseTree->superparents[regularNode]; + const FieldType& dataValue, // same as baseTree->dataValues[regularNode] + const InFieldPortalType& baseTreeSuperarcsPortal, + const InFieldPortalType& newSupernodeIdsPortal, + const ExecObjectType1& findRegularByGlobal, // Execution object to call FindRegularByGlobal + const ExecObjectType2& + findSuperArcForUnknownNode, // Execution object to call FindSuperArcForUnknownNode + vtkm::Id& + regularSuperparentsValue, // same as regularSuperparents[regularNode] = ... (set on output) + vtkm::Id& + regularNodesNeededValue // same as regularNodesNeeded[regularNode] = ... (set on output) + ) const + { + // per regular node + // retrieve the index (globalRegularId set on input) + // first check to see if it is already present (newRegularId set on input) + vtkm::Id newRegularId = findRegularByGlobal.FindRegularByGlobal(globalRegularId); + + // if it fails this test, then it's already in tree + if (vtkm::worklet::contourtree_augmented::NoSuchElement(newRegularId)) + { // not yet in tree + // since it's not in the tree, we want to find where it belongs + // to do so, we need to find an "above" and "below" node for it. Since it exists in the old tree, it belongs to a superarc, and we + // can use the ends of the superarc as above and below to do the searching + // oldSuperparent set on Input vtkm::Id oldSuperparent = baseTree->superparents[regularNode]; + vtkm::Id oldSuperarc = baseTreeSuperarcsPortal.Get(oldSuperparent); + + // break the superarc into the flag and the target + // NOTE that we do not test for NO_SUCH_ELEMENT as all attachment points and the root are guaranteed to be present already, + // and have therefore been excluded by the if statement already + vtkm::Id oldSuperTarget = vtkm::worklet::contourtree_augmented::MaskedIndex(oldSuperarc); + bool ascendingSuperarc = vtkm::worklet::contourtree_augmented::IsAscending(oldSuperarc); + + // convert both from and to into new supernode IDs + vtkm::Id newSuperparent = newSupernodeIdsPortal.Get(oldSuperparent); + vtkm::Id newSuperTarget = newSupernodeIdsPortal.Get(oldSuperTarget); + + // retrieve the data value (dataValue set on input) + // now test and retrieve, with above = target if ascending, &c. + if (ascendingSuperarc) + { + regularSuperparentsValue = findSuperArcForUnknownNode.FindSuperArcForUnknownNode( + globalRegularId, dataValue, newSuperTarget, newSuperparent); + } + else + { + regularSuperparentsValue = findSuperArcForUnknownNode.FindSuperArcForUnknownNode( + globalRegularId, dataValue, newSuperparent, newSuperTarget); + } + // either way, we set the index array to the index + regularNodesNeededValue = regularNode; + } // not yet in tree + // Set to NO_SUCH_ELEMENT by default. By doing this in the worklet we an avoid having to + // initialize the output arrays first and we can use FieldIn instead of FieldInOut + else + { + regularSuperparentsValue = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT; + regularNodesNeededValue = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT; + } + + // In serial this worklet implements the following operation + /* + // now loop, finding the superparent for each node needed + for (vtkm::Id regularNode = 0; regularNode < baseTree->regularNodeGlobalIDs.size(); regularNode++) + { // per regular node + // retrieve the index + vtkm::Id globalRegularID = baseTree->regularNodeGlobalIDs[regularNode]; + + // first check to see if it is already present + vtkm::Id newRegularID = augmentedTree->FindRegularByGlobal(globalRegularID); + + // if it fails this test, then it's already in tree + if (noSuchElement(newRegularID)) + { // not yet in tree + // std::cout << "Not yet in tree" << std::endl; + // since it's not in the tree, we want to find where it belongs + // to do so, we need to find an "above" and "below" node for it. Since it exists in the old tree, it belongs to a superarc, and we + // can use the ends of the superarc as above and below to do the searching + vtkm::Id oldSuperparent = baseTree->superparents[regularNode]; + vtkm::Id oldSuperarc = baseTree->superarcs[oldSuperparent]; + + // break the superarc into the flag and the target + // NOTE that we do not test for NO_SUCH_ELEMENT as all attachment points and the root are guaranteed to be present already, + // and have therefore been excluded by the if statement already + vtkm::Id oldSuperTarget = maskedIndex(oldSuperarc); + bool ascendingSuperarc = isAscending(oldSuperarc); + + // convert both from and to into new supernode IDs + vtkm::Id newSuperparent = newSupernodeIDs[oldSuperparent]; + vtkm::Id newSuperTarget = newSupernodeIDs[oldSuperTarget]; + + // retrieve the data value + dataType dataValue = baseTree->dataValues[regularNode]; + + // now test and retrieve, with above = target if ascending, &c. + if (ascendingSuperarc) + regularSuperparents[regularNode] = augmentedTree->FindSuperArcForUnknownNode(globalRegularID, dataValue, newSuperTarget, newSuperparent); + else + regularSuperparents[regularNode] = augmentedTree->FindSuperArcForUnknownNode(globalRegularID, dataValue, newSuperparent, newSuperTarget); + + // either way, we set the index array to the index + regularNodesNeeded[regularNode] = regularNode; + } // not yet in tree + } // per regular node + */ + } // operator()() + +}; // FindSuperparentForNecessaryNodesWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAscendingDecorator.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAscendingDecorator.h new file mode 100644 index 000000000..8abb8baa4 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAscendingDecorator.h @@ -0,0 +1,94 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_is_ascending_decorator_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_is_ascending_decorator_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Decorator to add the Ascending flag if necessary +class IsAscendingDecorator +{ +public: + template + struct Functor + { + PortalType1 SuperparentsPortal; + PortalType2 SuperarcsPortal; + + VTKM_EXEC_CONT vtkm::Id operator()(vtkm::Id i) const + { + vtkm::Id superparent = this->SuperparentsPortal.Get(i); + if (vtkm::worklet::contourtree_augmented::IsAscending(this->SuperarcsPortal.Get(superparent))) + { + superparent |= vtkm::worklet::contourtree_augmented::IS_ASCENDING; + } + return superparent; + } + }; + + template + Functor CreateFunctor(PT1 SuperparentsPortal, PT2 SuperarcsPortal) const + { + return { SuperparentsPortal, SuperarcsPortal }; + } +}; + +} // namespace hierarchical_augmenter +} // namespace contourtree_augmented +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointNeededPredicate.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointNeededPredicate.h new file mode 100644 index 000000000..697b3839b --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointNeededPredicate.h @@ -0,0 +1,143 @@ +//============================================================================ +// 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_augmenter_is_attachement_point_needed_predicate_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_is_attachement_point_needed_predicate_h + +#include +#include +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +// Implementatin of predicate used in HierarchicalAugmenter::PrepareOutAttachmentPoints +// to determine whether an attachement points needs to be transferred +class IsAttachementPointNeededPredicateImpl +{ +public: + using IdPortalType = vtkm::worklet::contourtree_augmented::IdArrayType::ReadPortalType; + + // constructor - takes vectors as parameters + VTKM_CONT + IsAttachementPointNeededPredicateImpl( + const vtkm::worklet::contourtree_augmented::IdArrayType& superparentsRounds, + const vtkm::worklet::contourtree_augmented::IdArrayType& whichRounds, + const vtkm::Id round, + vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) + : SuperparentsRoundsPortal(superparentsRounds.PrepareForInput(device, token)) + , WhichRoundsPortal(whichRounds.PrepareForInput(device, token)) + , Round(round) + { // constructor + } // constructor + + // () operator - gets called to do comparison + VTKM_EXEC + bool operator()(const vtkm::Id& attachmentPoint) const + { // operator() + return !((this->SuperparentsRoundsPortal.Get(attachmentPoint) <= this->Round) || + (this->WhichRoundsPortal.Get(attachmentPoint) > this->Round)); + } // operator() + +private: + IdPortalType SuperparentsRoundsPortal; + IdPortalType WhichRoundsPortal; + const vtkm::Id Round; + + +}; // IsAttachementPointNeededPredicateImpl + + +// Predicate ExecutonObject used in HierarchicalAugmenter::PrepareOutAttachmentPoints +// to determine whether an attachement points needs to be transferred +class IsAttachementPointNeededPredicate : public vtkm::cont::ExecutionObjectBase +{ +public: + // constructor - takes vectors as parameters + VTKM_CONT + IsAttachementPointNeededPredicate( + const vtkm::worklet::contourtree_augmented::IdArrayType& superparentsRounds, + const vtkm::worklet::contourtree_augmented::IdArrayType& whichRounds, + const vtkm::Id round) + : SuperparentsRounds(superparentsRounds) + , WhichRounds(whichRounds) + , Round(round) + { + } + + VTKM_CONT IsAttachementPointNeededPredicateImpl + PrepareForExecution(vtkm::cont::DeviceAdapterId device, vtkm::cont::Token& token) const + { + return IsAttachementPointNeededPredicateImpl( + this->SuperparentsRounds, this->WhichRounds, this->Round, device, token); + } + +private: + vtkm::worklet::contourtree_augmented::IdArrayType SuperparentsRounds; + vtkm::worklet::contourtree_augmented::IdArrayType WhichRounds; + const vtkm::Id Round; +}; // IsAttachementPointNeededPredicate + +} // namespace hierarchical_augmenter +} // namespace contourtree_augmented +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointPredicate.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointPredicate.h new file mode 100644 index 000000000..e8b343d13 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/IsAttachementPointPredicate.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_augmenter_is_attachement_point_predicate_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_is_attachement_point_predicate_h + +#include +#include +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + + +/// Predicate used in HierarchicalAugmenter::Initalize to determine +/// whether a node is an attachement point +class IsAttachementPointPredicateImpl +{ +public: + using IdPortalType = vtkm::worklet::contourtree_augmented::IdArrayType::ReadPortalType; + + // constructor - takes vectors as parameters + VTKM_CONT + IsAttachementPointPredicateImpl( + const vtkm::worklet::contourtree_augmented::IdArrayType& superarcs, + const vtkm::worklet::contourtree_augmented::IdArrayType& whichRound, + const vtkm::Id numRounds, + vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) + : SuperarcsPortal(superarcs.PrepareForInput(device, token)) + , WhichRoundPortal(whichRound.PrepareForInput(device, token)) + , NumRounds(numRounds) + { // constructor + } // constructor + + // () operator - gets called to do comparison + VTKM_EXEC + bool operator()(const vtkm::Id& supernode) const + { // operator() + return ( + vtkm::worklet::contourtree_augmented::NoSuchElement(this->SuperarcsPortal.Get(supernode)) && + (this->WhichRoundPortal.Get(supernode) < this->NumRounds)); + } // operator() + +private: + IdPortalType SuperarcsPortal; + IdPortalType WhichRoundPortal; + const vtkm::Id NumRounds; + + +}; // IsAttachementPointPredicateImpl + +class IsAttachementPointPredicate : public vtkm::cont::ExecutionObjectBase +{ +public: + // constructor - takes vectors as parameters + VTKM_CONT + IsAttachementPointPredicate(const vtkm::worklet::contourtree_augmented::IdArrayType& superarcs, + const vtkm::worklet::contourtree_augmented::IdArrayType& whichRound, + const vtkm::Id numRounds) + : Superarcs(superarcs) + , WhichRound(whichRound) + , NumRounds(numRounds) + { + } + + VTKM_CONT IsAttachementPointPredicateImpl PrepareForExecution(vtkm::cont::DeviceAdapterId device, + vtkm::cont::Token& token) const + { + return IsAttachementPointPredicateImpl( + this->Superarcs, this->WhichRound, this->NumRounds, device, token); + } + +private: + vtkm::worklet::contourtree_augmented::IdArrayType Superarcs; + vtkm::worklet::contourtree_augmented::IdArrayType WhichRound; + const vtkm::Id NumRounds; +}; // IsAttachementPointPredicate + +} // namespace hierarchical_augmenter +} // namespace contourtree_augmented +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/NotNoSuchElementPredicate.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/NotNoSuchElementPredicate.h new file mode 100644 index 000000000..7f07dc0b0 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/NotNoSuchElementPredicate.h @@ -0,0 +1,89 @@ +//============================================================================ +// 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_augmenter_not_no_such_element_predicate_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_not_no_such_element_predicate_h + +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + + +//Simple functor to subset a VTKm ArrayHandle +class NotNoSuchElementPredicate +{ +public: + VTKM_EXEC_CONT + NotNoSuchElementPredicate() {} + + VTKM_EXEC_CONT + bool operator()(const vtkm::Id& inId) const + { + return !static_cast(vtkm::worklet::contourtree_augmented::NoSuchElement(inId)); + } + +private: +}; + +} // namespace data_set_mesh +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/ResizeArraysBuildNewSupernodeIdsWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/ResizeArraysBuildNewSupernodeIdsWorklet.h new file mode 100644 index 000000000..af9021fcf --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/ResizeArraysBuildNewSupernodeIdsWorklet.h @@ -0,0 +1,135 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_resize_arrays_build_new_supernode_ids_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_resize_arrays_build_new_supernode_ids_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalAugmenterResizeArrays to build the newSupernodeIds array +class ResizeArraysBuildNewSupernodeIdsWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + using ControlSignature = void( + FieldIn supernodeIndex, // input domain ArrayHandleIndex(SupernodeSorter.GetNumberOfValues()) + FieldIn + supernodeIdSetPermuted, // input supernodeIDSet permuted by supernodeSorter to allow for FieldIn + WholeArrayInOut + newSupernodeIds // output/input (both are necessary since not all valyes will be overwritten) + ); + using ExecutionSignature = void(InputIndex, _1, _2, _3); + using InputDomain = _1; + + // Default Constructor + VTKM_EXEC_CONT + ResizeArraysBuildNewSupernodeIdsWorklet(const vtkm::Id& numSupernodesAlready) + : NumSupernodesAlready(numSupernodesAlready) + { + } + + template + VTKM_EXEC void operator()( + const vtkm::Id& supernode, // InputIndex of supernodeSorter + const vtkm::Id& oldSupernodeId, // same as supernodeIDSet[supernodeSetIndex]; + const InOutFieldPortalType& newSupernodeIdsPortal) const + { + // per supernode + // retrieve the index from the sorting index array. supernodeSetIndex set on input + + // work out the correct new supernode ID + vtkm::Id newSupernodeId = this->NumSupernodesAlready + supernode; + + // retrieve the old supernode ID from the sorting array, remembering + // that if it came from another block it will be set to NO_SUCH_ELEMENT + // vtkm::Id oldSupernodeId set on input since we use ArrayHandlePermutation to + // shuffle supernodeIDSet by supernodeSorter; + + // and write to the lookup array + if (!vtkm::worklet::contourtree_augmented::NoSuchElement(oldSupernodeId)) + { + newSupernodeIdsPortal.Set(oldSupernodeId, newSupernodeId); + } + + // In serial this worklet implements the following operation + /* + for (vtkm::Id supernode = 0; supernode < supernodeSorter.size(); supernode++) + { // per supernode + // retrieve the index from the sorting index array + vtkm::Id supernodeSetIndex = supernodeSorter[supernode]; + + // work out the correct new supernode ID + vtkm::Id newSupernodeID = numSupernodesAlready + supernode; + + // retrieve the old supernode ID from the sorting array, remembering that if it came from another block it will be set to NO_SUCH_ELEMENT + vtkm::Id oldSupernodeID = supernodeIDSet[supernodeSetIndex]; + + // and write to the lookup array + if (!noSuchElement(oldSupernodeID)) + newSupernodeIDs[oldSupernodeID] = newSupernodeID; + } // per supernode + */ + } // operator()() +private: + const vtkm::Id NumSupernodesAlready; + +}; // ResizeArraysBuildNewSupernodeIdsWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetFirstAttachmentPointInRoundWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetFirstAttachmentPointInRoundWorklet.h new file mode 100644 index 000000000..e517f08dc --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetFirstAttachmentPointInRoundWorklet.h @@ -0,0 +1,146 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_set_first_attachment_point_in_round_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_set_first_attachment_point_in_round_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalHyperSweeper.TransferWeights(...) to implement +/// step 7b. Now find the LHE of each group and subtract out the prior weight +class SetFirstAttachmentPointInRoundWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + /// NOTE: we need this to be in/out because any valyes we don't set here need + /// to remain NO_SUCH_ELEMENT for further processing + using ControlSignature = void(WholeArrayIn attachmentIds, // input + WholeArrayIn superparentRounds, // input + WholeArrayInOut firstAttachmentPointInRound // input/output + + ); + using ExecutionSignature = void(InputIndex, _1, _2, _3); + using InputDomain = _1; + + // Default Constructor + VTKM_EXEC_CONT + SetFirstAttachmentPointInRoundWorklet() {} + + template + VTKM_EXEC void operator()(const vtkm::Id& attachmentPoint, + const InFieldPortalType& attachmentIdsPortal, + const InFieldPortalType& superparentRoundsPortal, + const InOutFieldPortalType& firstAttachmentPointInRoundPortal) const + { + // per attachment point + // retrieve the ID of the attachment point + vtkm::Id attachmentPointId = attachmentIdsPortal.Get(attachmentPoint); + // the 0th element always starts a segment, so set the round's beginning + if (attachmentPoint == 0) + { + firstAttachmentPointInRoundPortal.Set(superparentRoundsPortal.Get(attachmentPointId), + static_cast(0)); + } + // otherwise, a segment begins when it's SP round is different from the next one down + else + { // not the beginning of the array + // retrieve the two attachment point IDs + vtkm::Id previousAttachmentPointId = attachmentIdsPortal.Get(attachmentPoint - 1); + // and the corresponding superparent rounds + vtkm::Id superparentRound = superparentRoundsPortal.Get(attachmentPointId); + vtkm::Id previousSuperparentRound = superparentRoundsPortal.Get(previousAttachmentPointId); + // detect where the segment ID changes & use that to set the value + if (superparentRound != previousSuperparentRound) + { + firstAttachmentPointInRoundPortal.Set(superparentRound, attachmentPoint); + } + } // not the beginning of the array + + + // In serial this worklet implements the following operation + /* + for (vtkm::Id attachmentPoint = 0; attachmentPoint < attachmentIDs.size(); attachmentPoint++) + { // per attachment point + // retrieve the ID of the attachment point + vtkm::Id attachmentPointID = attachmentIDs[attachmentPoint]; + // the 0th element always starts a segment, so set the round's beginning + if (attachmentPoint == 0) + firstAttachmentPointInRound[superparentRounds[attachmentPointID]] = 0; + // otherwise, a segment begins when it's SP round is different from the next one down + else + { // not the beginning of the array + // retrieve the two attachment point IDs + vtkm::Id previousAttachmentPointID = attachmentIDs[attachmentPoint-1]; + // and the corresponding superparent rounds + vtkm::Id superparentRound = superparentRounds[attachmentPointID]; + vtkm::Id previousSuperparentRound = superparentRounds[previousAttachmentPointID]; + + // detect where the segment ID changes & use that to set the value + if (superparentRound != previousSuperparentRound) + firstAttachmentPointInRound[superparentRound] = attachmentPoint; + } // not the beginning of the array + + } // per attachment point + + */ + } // operator()() +}; // SetFirstAttachmentPointInRoundWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetSuperparentSetDecorator.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetSuperparentSetDecorator.h new file mode 100644 index 000000000..b86c8029a --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/SetSuperparentSetDecorator.h @@ -0,0 +1,94 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_set_superparent_set_decorator_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_set_superparent_set_decorator_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Decorator to add the Ascending flag if necessary +class SetSuperparentSetDecorator +{ +public: + template + struct Functor + { + PortalType1 KeptSupernodesPortal; + PortalType2 BaseTreeSuperarcsPortal; + + VTKM_EXEC_CONT vtkm::Id operator()(vtkm::Id i) const + { + vtkm::Id oldSupernodeId = KeptSupernodesPortal.Get(i); + return (oldSupernodeId | + (vtkm::worklet::contourtree_augmented::IsAscending( + BaseTreeSuperarcsPortal.Get(oldSupernodeId)) + ? vtkm::worklet::contourtree_augmented::IS_ASCENDING + : 0x00)); + } + }; + + template + Functor CreateFunctor(PT1 KeptSupernodesPortal, PT2 BaseTreeSuperarcsPortal) const + { + return { KeptSupernodesPortal, BaseTreeSuperarcsPortal }; + } +}; + +} // namespace hierarchical_augmenter +} // namespace contourtree_augmented +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetHyperarcsAndNodesWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetHyperarcsAndNodesWorklet.h new file mode 100644 index 000000000..897fa6f03 --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetHyperarcsAndNodesWorklet.h @@ -0,0 +1,153 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_update_hyperstructure_set_hyperarcs_and_nodes_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_update_hyperstructure_set_hyperarcs_and_nodes_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalAugmenter::UpdateHyperstructure to set the hyperarcs and hypernodes +class UpdateHyperstructureSetHyperarcsAndNodesWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + using ControlSignature = void(FieldIn baseTreeHypernodes, // input + FieldIn baseTreeHyperarcs, // input + WholeArrayIn newSupernodeIds, // input + FieldOut augmentedTreeHypernodes, // output + FieldOut augmentedTreeHyperarcs // output + ); + using ExecutionSignature = void(_1, _2, _3, _4, _5); + using InputDomain = _1; + + // Default Constructor + VTKM_EXEC_CONT + UpdateHyperstructureSetHyperarcsAndNodesWorklet() {} + + template + VTKM_EXEC void operator()( + const vtkm::Id& oldHypernodeSuperId, // same as baseTree->hypernodes[hypernode] + const vtkm::Id& oldTargetSuperIdMasked, // same as baseTree->hyperarcs[hypernode] + const InFieldPortalType& newSupernodeIdsPortal, + vtkm::Id& outAugmentedTreeHypernodesValue, // same as augmentedTree->hypernodes[hypernode] = ... + vtkm::Id& outAugmentedTreeHyperarcsValue // same as augmentedTree->hyperarcs[hypernode] = ... + ) const + { + // per hypernode + // retrieve existing values which are in old supernode Ids + // oldHypernodeSuperId and oldTargetSuperIdMasked are set by the worklt + // strip out the ascending flag & the flag for root hyperarc + bool isRootHyperarc = + vtkm::worklet::contourtree_augmented::NoSuchElement(oldTargetSuperIdMasked); + bool hyperarcAscends = + vtkm::worklet::contourtree_augmented::IsAscending(oldTargetSuperIdMasked); + vtkm::Id oldTargetSuperId = + vtkm::worklet::contourtree_augmented::MaskedIndex(oldTargetSuperIdMasked); + + // lookup new values + vtkm::Id newHypernodeSuperId = newSupernodeIdsPortal.Get(oldHypernodeSuperId); + vtkm::Id newTargetSuperId = vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT; + if (!isRootHyperarc) + { // not the root + // lookup the new ID + newTargetSuperId = newSupernodeIdsPortal.Get(oldTargetSuperId); + if (hyperarcAscends) + { + newTargetSuperId |= vtkm::worklet::contourtree_augmented::IS_ASCENDING; + } + } // not the root + + // now store them + outAugmentedTreeHypernodesValue = newHypernodeSuperId; + outAugmentedTreeHyperarcsValue = newTargetSuperId; + + // In serial this worklet implements the following operation + /* + for (vtkm::Id hypernode = 0; hypernode < augmentedTree->hypernodes.size(); hypernode++) + { // per hypernode + // retrieve existing values which are in old supernode IDs + vtkm::Id oldHypernodeSuperID = baseTree->hypernodes[hypernode]; + vtkm::Id oldTargetSuperID = baseTree->hyperarcs[hypernode]; + // strip out the ascending flag & the flag for root hyperarc + bool isRootHyperarc = noSuchElement(oldTargetSuperID); + bool hyperarcAscends = isAscending(oldTargetSuperID); + oldTargetSuperID = maskedIndex(oldTargetSuperID); + + // lookup new values + vtkm::Id newHypernodeSuperID = newSupernodeIDs[oldHypernodeSuperID]; + vtkm::Id newTargetSuperID = NO_SUCH_ELEMENT; + if (!isRootHyperarc) + { // not the root + // lookup the new ID + newTargetSuperID = newSupernodeIDs[oldTargetSuperID]; + if (hyperarcAscends) + newTargetSuperID |= IS_ASCENDING; + } // not the root + + // now store them + augmentedTree->hypernodes[hypernode] = newHypernodeSuperID; + augmentedTree->hyperarcs[hypernode] = newTargetSuperID; + } // per hypernode + + */ + } // operator()() +}; // UpdateHyperstructureSetHyperarcsAndNodesWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif diff --git a/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetSuperchildrenWorklet.h b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetSuperchildrenWorklet.h new file mode 100644 index 000000000..9890fec8f --- /dev/null +++ b/vtkm/worklet/contourtree_distributed/hierarchical_augmenter/UpdateHyperstructureSetSuperchildrenWorklet.h @@ -0,0 +1,135 @@ +//============================================================================ +// 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. +// +//============================================================================= +// 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_augmenter_update_hyperstructure_set_superchildren_worklet_h +#define vtk_m_worklet_contourtree_distributed_hierarchical_augmenter_update_hyperstructure_set_superchildren_worklet_h + +#include +#include + +namespace vtkm +{ +namespace worklet +{ +namespace contourtree_distributed +{ +namespace hierarchical_augmenter +{ + +/// Worklet used in HierarchicalAugmenter::UpdateHyperstructure to set the superchildren +/// The worklet finds the number of superchildren as the delta between the super Id +/// and the next hypernode's super Id +class UpdateHyperstructureSetSuperchildrenWorklet : public vtkm::worklet::WorkletMapField +{ +public: + /// Control signature for the worklet + using ControlSignature = void( + WholeArrayIn augmentedTreeHypernodes, // input (we need both this and the next value) + FieldOut augmentedTreeSuperchildren // output + ); + using ExecutionSignature = void(InputIndex, _1, _2); + using InputDomain = _1; + + // Default Constructor + VTKM_EXEC_CONT + UpdateHyperstructureSetSuperchildrenWorklet(const vtkm::Id& augmentedTreeNumSupernodes) + : AugmentedTreeNumSupernodes(augmentedTreeNumSupernodes) + { + } + + + template + VTKM_EXEC void operator()( + const vtkm::Id& hypernode, + const InFieldPortalType& augmentedTreeHypernodesPortal, + vtkm::Id& + augmentedTreeSuperchildrenValue // same as augmentedTree->superchildren[InputIndex] = ... + ) const + { + // per hypernode + // retrieve the new superId + vtkm::Id superId = augmentedTreeHypernodesPortal.Get(hypernode); + // and the next one over + vtkm::Id nextSuperId; + if (hypernode == augmentedTreeHypernodesPortal.GetNumberOfValues() - 1) + { + nextSuperId = this->AugmentedTreeNumSupernodes; + } + else + { + nextSuperId = augmentedTreeHypernodesPortal.Get(hypernode + 1); + } + // the difference is the number of superchildren + augmentedTreeSuperchildrenValue = nextSuperId - superId; + + // In serial this worklet implements the following operation + /* + for (vtkm::Id hypernode = 0; hypernode < augmentedTree->hypernodes.size(); hypernode++) + { // per hypernode + // retrieve the new super ID + vtkm::Id superID = augmentedTree->hypernodes[hypernode]; + // and the next one over + vtkm::Id nextSuperID; + if (hypernode == augmentedTree->hypernodes.size() - 1) + nextSuperID = augmentedTree->supernodes.size(); + else + nextSuperID = augmentedTree->hypernodes[hypernode+1]; + // the difference is the number of superchildren + augmentedTree->superchildren[hypernode] = nextSuperID - superID; + } // per hypernode + + */ + } // operator()() + +private: + const vtkm::Id AugmentedTreeNumSupernodes; +}; // UpdateHyperstructureSetSuperchildrenWorklet + +} // namespace hierarchical_augmenter +} // namespace contourtree_distributed +} // namespace worklet +} // namespace vtkm + +#endif