VTK-m  2.0
HierarchicalHyperSweeper.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 // Copyright (c) 2018, The Regents of the University of California, through
11 // Lawrence Berkeley National Laboratory (subject to receipt of any required approvals
12 // from the U.S. Dept. of Energy). All rights reserved.
13 //
14 // Redistribution and use in source and binary forms, with or without modification,
15 // are permitted provided that the following conditions are met:
16 //
17 // (1) Redistributions of source code must retain the above copyright notice, this
18 // list of conditions and the following disclaimer.
19 //
20 // (2) Redistributions in binary form must reproduce the above copyright notice,
21 // this list of conditions and the following disclaimer in the documentation
22 // and/or other materials provided with the distribution.
23 //
24 // (3) Neither the name of the University of California, Lawrence Berkeley National
25 // Laboratory, U.S. Dept. of Energy nor the names of its contributors may be
26 // used to endorse or promote products derived from this software without
27 // specific prior written permission.
28 //
29 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
30 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
31 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
36 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
37 // OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
38 // OF THE POSSIBILITY OF SUCH DAMAGE.
39 //
40 //=======================================================================================
41 //
42 // Parallel Peak Pruning v. 2.0
43 //
44 // Started June 15, 2017
45 //
46 // Copyright Hamish Carr, University of Leeds
47 //
48 // HierarchicalHyperSweeper.h
49 //
50 //=======================================================================================
51 //
52 // COMMENTS:
53 //
54 // This class encapsulates a hypersweep over the hierarchical contour tree. It is a
55 // separate class primarily to keep the post-processing separate from the main tree
56 // construction, but it should also make it easier to generalise to arbitrary computations
57 //
58 // Basically, the way that this operates is:
59 // 1. First, we do a local (standard) hypersweep over the hierarchical tree
60 // 2. We then fan-in one round at a time. In each round,
61 // a. We trade the prefix of the array with our logical partner, then
62 // b. Combine the array prefix with our own
63 //
64 // Tactically, when we do MPI, we can either embed it in this unit, or leave it in the
65 // calling unit. For ease of porting, we will leave all MPI in the calling unit, so
66 // this unit only needs to do the combination.
67 //
68 // Note that we could define an operator to be passed in, and probably want to template it
69 // that way in the future, but for now, we'll do the first version directly with addition
70 //
71 // By assumption, we need a commutative property, since we do not guarantee that we have
72 // strict ordering along superarcs (which would require sharing a supernode sort with our
73 // partner, if not globally)
74 //
75 //=======================================================================================
76 
77 #ifndef vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_h
78 #define vtk_m_worklet_contourtree_distributed_hierarchical_hyper_sweeper_h
79 
80 #include <iomanip>
81 #include <string>
95 
96 
97 namespace vtkm
98 {
99 namespace worklet
100 {
101 namespace contourtree_distributed
102 {
103 
104 // the class itself
105 template <typename SweepValueType, typename ContourTreeFieldType>
107 { // class HierarchicalHyperSweeper
108 public:
109  // the tree that it hypersweeps over
111 
112  // the Id of the base block (used for debug output)
114 
115  // array of values being operated over (same size as supernode set)
116  // keep both intrinsic & dependent values
117  // the intrinsic values are just stored but not modifid here
119  // the dependent values are what is being sweeped and are updated here
121  // and to avoid an extra log summation, store the number of logical nodes for the underlying block
122  // (computed when initializing the regular vertex list)
124 
125 
126  // these are working arrays, lifted up here for ease of debug code
127  // Subranges of these arrays will be reused in the rounds / iterations rather than being reallocated
128  // an array for temporary storage of the prefix sums
130  // two arrays for collecting targets of transfers
133  // an array for indirect sorting of sets of superarcs
135 
143  vtkm::Id blockId,
144  const HierarchicalContourTree<ContourTreeFieldType>& hierarchicalTree,
145  const vtkm::cont::ArrayHandle<SweepValueType>& intrinsicValues,
146  const vtkm::cont::ArrayHandle<SweepValueType>& dependentValues);
147 
154  template <typename MeshType>
156  const HierarchicalContourTree<ContourTreeFieldType>& hierarchicalTree,
157  const MeshType& baseBlock,
158  const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler& localToGlobalIdRelabeler,
160 
164  void LocalHyperSweep();
165 
170  std::string DebugPrint(std::string message, const char* fileName, long lineNum) const;
171 
175  void SaveHierarchicalContourTreeDot(std::string message, const char* outFileName) const;
176 
177 protected:
178  // Functions used internally be LocalHyperSweep to compute the local hyper sweep
179 
182  vtkm::Id iteration,
183  vtkm::Id firstSupernode,
184  vtkm::Id lastSupernode);
185 
188  vtkm::Id iteration,
189  vtkm::Id firstSupernode,
190  vtkm::Id lastSupernode);
191 
193  void TransferWeights(vtkm::Id round,
194  vtkm::Id iteration,
195  vtkm::Id firstSupernode,
196  vtkm::Id lastSupernode);
197 
198 private:
201 
202 }; // class HierarchicalHyperSweeper
203 
204 
205 template <typename SweepValueType, typename ContourTreeFieldType>
207  vtkm::Id blockId,
208  const HierarchicalContourTree<ContourTreeFieldType>& hierarchicalTree,
209  const vtkm::cont::ArrayHandle<SweepValueType>& intrinsicValues,
210  const vtkm::cont::ArrayHandle<SweepValueType>& dependentValues)
211  : HierarchicalTree(hierarchicalTree)
212  , BlockId(blockId)
213  , IntrinsicValues(intrinsicValues)
214  , DependentValues(dependentValues)
215  , NumOwnedRegularVertices(vtkm::Id{ 0 })
216 { // constructor
217  // Initalize arrays with 0s
218  this->ValuePrefixSum.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
219  this->TransferTarget.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
220  this->SortedTransferTarget.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(),
221  0);
222  // Initialize the supersortPermute to the identity
223  vtkm::cont::ArrayHandleIndex tempIndexArray(
224  this->HierarchicalTree.Supernodes.GetNumberOfValues());
225  vtkm::cont::Algorithm::Copy(tempIndexArray, this->SuperSortPermute);
226 } // constructor
227 
228 
229 // static function used to compute the initial superarc regular counts
230 template <typename SweepValueType, typename ContourTreeFieldType>
231 template <typename MeshType>
233  const HierarchicalContourTree<ContourTreeFieldType>& hierarchicalTree,
234  const MeshType& baseBlock,
235  const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler& localToGlobalIdRelabeler,
237 { // InitializeIntrinsicVertexCount()
238  // I. Call the mesh to get a list of all regular vertices belonging to the block by global Id
240  // TODO/FIXME: Even though the virtual function on DataSetMesh was removed in commit
241  // 93730495813f7b85e59d4a5dae2076977787fd78, this should call the correct function
242  // since MeshType is templated and should have the appropriate type. Verify that
243  // this is indeed correct.
244  baseBlock.GetOwnedVerticesByGlobalId(localToGlobalIdRelabeler, globalIds);
245  // and store the size for later reference
246  //hierarchicalTree.NumOwnedRegularVertices = globalIds.GetNumberOfValues();
247  this->NumOwnedRegularVertices = globalIds.GetNumberOfValues();
248 
249 #ifdef DEBUG_PRINT
250  {
251  std::stringstream debugStream;
252  debugStream << std::endl << "Owned Regular Vertex List" << std::endl;
254  vtkm::worklet::contourtree_augmented::PrintIndices("GlobalId", globalIds, -1, debugStream);
255  VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
256  }
257 #endif
258 
259  // II. Look up the global Ids in the hierarchical tree & convert to superparent Ids
261  { // scope to make sure temporary variables are deleted
262  auto findRegularByGlobal = hierarchicalTree.GetFindRegularByGlobal();
263  auto computeSuperparentIdsWorklet = vtkm::worklet::contourtree_distributed::
264  hierarchical_hyper_sweeper::InitializeIntrinsicVertexCountComputeSuperparentIdsWorklet();
265  Invoke(computeSuperparentIdsWorklet, // worklet to run
266  globalIds, // input
267  findRegularByGlobal, // input
268  hierarchicalTree.Regular2Supernode, // input
269  hierarchicalTree.Superparents, // input
270  superparents // output
271  );
272  }
273 
274 #ifdef DEBUG_PRINT
275  {
276  std::stringstream debugStream;
278  "Superparents", superparents, -1, debugStream);
279  VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
280  }
281 #endif
282 
283  // III. Sort the superparent Ids & count the copies of each
284  vtkm::cont::Algorithm ::Sort(superparents);
285 
286 #ifdef DEBUG_PRINT
287  {
288  std::stringstream debugStream;
289  vtkm::worklet::contourtree_augmented::PrintIndices("Sorted SP", superparents, -1, debugStream);
290  VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
291  }
292 #endif
293 
294  // initialize the counts to zero.
295  superarcRegularCounts.AllocateAndFill(this->HierarchicalTree.Supernodes.GetNumberOfValues(), 0);
296 
297  // set the count to the Id one off the high end of each range
299  InitializeIntrinsicVertexCountInitalizeCountsWorklet{},
300  superparents, // input domain
301  superarcRegularCounts // output
302  );
303 
304  // now repeat to subtract out the low end
306  InitializeIntrinsicVertexCountSubtractLowEndWorklet{},
307  superparents, // input domain
308  superarcRegularCounts // output
309  );
310  // and that is that
311 #ifdef DEBUG_PRINT
312  {
313  std::stringstream debugStream;
315  "SuperarcRegularCounts", superarcRegularCounts, -1, debugStream);
316  VTKM_LOG_S(vtkm::cont::LogLevel::Info, debugStream.str());
317  }
318 #endif
319 } // InitializeIntrinsicVertexCount()
320 
321 
322 // routine to do the local hypersweep using addition / subtraction
323 template <typename SweepValueType, typename ContourTreeFieldType>
325 { // LocalHyperSweep()
326 #ifdef DEBUG_PRINT
328  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
329  std::string(" Starting Local HyperSweep"),
330  __FILE__,
331  __LINE__));
332 #endif
333 
334  // I. Iterate over all rounds of the hyperstructure
335  for (vtkm::Id round = 0; round <= this->HierarchicalTree.NumRounds; round++)
336  { // per round
337 #ifdef DEBUG_PRINT
339  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
340  std::string(" Round ") + std::to_string(round) +
341  std::string(" Step 0 Starting Round"),
342  __FILE__,
343  __LINE__));
344 #endif
345  // A. Iterate over all iterations of the round
346  auto numIterationsPortal =
347  this->HierarchicalTree.NumIterations
348  .ReadPortal(); // TODO/FIXME: Use portal? Or something more efficient?
349  for (vtkm::Id iteration = 0; iteration < numIterationsPortal.Get(round); iteration++)
350  { // per iteration
351 #ifdef DEBUG_PRINT
353  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
354  std::string(" Round ") + std::to_string(round) +
355  std::string(" Step 1 Iteration ") + std::to_string(iteration) +
356  std::string(" Step A Starting Iteration"),
357  __FILE__,
358  __LINE__));
359 #endif
360  // 1. Establish the range of supernode Ids that we want to process
361  // TODO/FIXME: Use portal? Or is there a more efficient way?
362  auto firstSupernodePerIterationPortal =
363  this->HierarchicalTree.FirstSupernodePerIteration[round].ReadPortal();
364  vtkm::Id firstSupernode = firstSupernodePerIterationPortal.Get(iteration);
365  vtkm::Id lastSupernode = firstSupernodePerIterationPortal.Get(iteration + 1);
366 
367  // call the routine that computes the dependent weights for each superarc in that range
368  this->ComputeSuperarcDependentWeights(round, iteration, firstSupernode, lastSupernode);
369 
370 #ifdef DEBUG_PRINT
372  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
373  std::string(" Round ") + std::to_string(round) +
374  std::string(" Step 1 Iteration ") + std::to_string(iteration) +
375  std::string(" Step B Dependent Weights Computed"),
376  __FILE__,
377  __LINE__));
378 #endif
379  // now call the routine that computes the weights to be transferred and the superarcs to which they transfer
380  this->ComputeSuperarcTransferWeights(round, iteration, firstSupernode, lastSupernode);
381 
382 #ifdef DEBUG_PRINT
384  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
385  std::string(" Round ") + std::to_string(round) +
386  std::string(" Step 1 Iteration ") + std::to_string(iteration) +
387  std::string(" Step C Transfer Weights Computed"),
388  __FILE__,
389  __LINE__));
390 #endif
391 
392  // transfer the weights
393  this->TransferWeights(round, iteration, firstSupernode, lastSupernode);
394 
395 #ifdef DEBUG_PRINT
397  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
398  std::string(" Round ") + std::to_string(round) +
399  std::string(" Step 1 Iteration ") + std::to_string(iteration) +
400  std::string(" Step D Weights Transferred"),
401  __FILE__,
402  __LINE__));
403 #endif
404  } // per iteration
405 
406 #ifdef DEBUG_PRINT
408  DebugPrint(std::string("Hypersweep Block ") + std::to_string(BlockId) +
409  std::string(" Round ") + std::to_string(round) +
410  std::string(" Step 2 Ending Round"),
411  __FILE__,
412  __LINE__));
413 #endif
414  } // per round
415 } // LocalHyperSweep()
416 
417 
418 // routine to compute the correct weights dependent on each superarc in a subrange (defined by the round & iteration)
419 template <typename SweepValueType, typename ContourTreeFieldType>
422  vtkm::Id round,
423  vtkm::Id, // iteration, // Kept parameter in case we need it for debugging.
424  vtkm::Id firstSupernode,
425  vtkm::Id lastSupernode)
426 { // ComputeSuperarcDependentWeights()
427  vtkm::Id numSupernodesToProcess = lastSupernode - firstSupernode;
428 
429  // 2. Use sorted prefix sum to compute the total weight to contribute to the super/hypertarget
430  // Same as std::partial_sum(sweepValues.begin() + firstSupernode, sweepValues.begin() + lastSupernode, valuePrefixSum.begin() + firstSupernode);
431  {
432  // DependentValues[firstSuperNode, lastSupernode)
434  dependentValuesView(this->DependentValues, // subset DependentValues
435  firstSupernode, // start at firstSupernode
436  numSupernodesToProcess); // until lastSuperNode (not inclued)
437  // Target array
439  valuePrefixSumView(this->ValuePrefixSum, // subset ValuePrefixSum
440  firstSupernode, // start at firstSupernode
441  numSupernodesToProcess); // until lastSuperNode (not inclued)
442  // Compute the partial sum for DependentValues[firstSuperNode, lastSupernode) and write to ValuePrefixSum[firstSuperNode, lastSupernode)
443  vtkm::cont::Algorithm::ScanInclusive(dependentValuesView, // input
444  valuePrefixSumView); // result of partial sum
445  }
446 
447  // Since the prefix sum is over *all* supernodes in the iteration, we need to break it into segments
448  // There are two cases we have to worry about:
449  // a. Hyperarcs made up of multiple supernodes
450  // b. Attachment points (which don't have a corresponding hyperarc)
451  // and they can be mixed in any given iteration
452 
453  // Since we have the prefix sum in a separate array, we avoid read/write conflicts
454 
455  // 3. Compute the segmented weights from the prefix sum array
456  {
457  // Create views of the subranges of the arrays we need to update
459  firstSupernode, vtkm::Id{ 1 }, numSupernodesToProcess);
461  hierarchicalTreeSuperarcsView(
462  this->HierarchicalTree.Superarcs, firstSupernode, numSupernodesToProcess);
464  hierarchicalTreeHyperparentsView(
465  this->HierarchicalTree.Hyperparents, firstSupernode, numSupernodesToProcess);
467  hierarchicalTreeHypernodesView(
468  this->HierarchicalTree.Hypernodes, firstSupernode, numSupernodesToProcess);
470  dependentValuesView(this->DependentValues, firstSupernode, numSupernodesToProcess);
471  // create the worklet
472  vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
473  ComputeSuperarcDependentWeightsWorklet<SweepValueType>
474  computeSuperarcDependentWeightsWorklet(
475  firstSupernode, round, this->HierarchicalTree.NumRounds);
476  // Execute the worklet
477  this->Invoke(
478  computeSuperarcDependentWeightsWorklet, // the worklet
479  supernodeIndex, // input counting index [firstSupernode, lastSupernode)
480  hierarchicalTreeSuperarcsView, // input view of hierarchicalTree.Superarcs[firstSupernode, lastSupernode)
481  hierarchicalTreeHyperparentsView, // input view of hierarchicalTree.Hyperparents[firstSupernode, lastSupernode)
482  this->HierarchicalTree.Hypernodes, // input full hierarchicalTree.Hypernodes array
483  this->ValuePrefixSum, // input full ValuePrefixSum array
484  dependentValuesView // output view of sweepValues[firstSu
485  );
486  }
487 } // ComputeSuperarcDependentWeights()
488 
489 
490 // routine to compute the weights to transfer to superarcs (defined by the round & iteration)
491 template <typename SweepValueType, typename ContourTreeFieldType>
493  vtkm::Id round,
494  vtkm::Id, // iteration, // Kept parameter in case we need it for debugging.
495  vtkm::Id firstSupernode,
496  vtkm::Id lastSupernode)
497 { // ComputeSuperarcTransferWeights()
498  // At this stage, we would otherwise transfer weights by hyperarc, but attachment points don't *have* hyperarcs
499  // so we will do a transfer by superarc instead, making sure that we only transfer from the last superarc in each
500  // hyperarc, plus for any attachment point
501  vtkm::Id numSupernodesToProcess = lastSupernode - firstSupernode;
502 
503  // 4. Set the amount each superarc wants to transfer, reusing the valuePrefixSum array for the purpose
504  // and the transfer target
505  { // scope ComputeSuperarcTransferWeightsWorklet to make sure temp variables are cleared
506  // Create ArrayHandleViews of the subrange of values that we need to update
508  firstSupernode, vtkm::Id{ 1 }, numSupernodesToProcess);
510  hierarchicalTreeSupernodesView(
511  this->HierarchicalTree.Supernodes, firstSupernode, numSupernodesToProcess);
513  hierarchicalTreeSuperarcsView(
514  this->HierarchicalTree.Superarcs, firstSupernode, numSupernodesToProcess);
516  transferTargetView(this->TransferTarget, firstSupernode, numSupernodesToProcess);
517  // instantiate the worklet
518  vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
519  ComputeSuperarcTransferWeightsWorklet computeSuperarcTransferWeightsWorklet(
520  round, this->HierarchicalTree.NumRounds, lastSupernode);
521  // call the worklet
522  this->Invoke(
523  computeSuperarcTransferWeightsWorklet, // worklet
524  supernodeIndex, // input counting array [firstSupernode, lastSupernode)
525  hierarchicalTreeSupernodesView, // input view of hierarchicalTree.supernodes[firstSupernode, lastSupernode)
526  this->HierarchicalTree.Superparents, // input whole array of hierarchicalTree.superparents
527  this->HierarchicalTree.Hyperparents, // input whole array of hierarchicalTree.hyperparents
528  hierarchicalTreeSuperarcsView, // input/output view of hierarchicalTree.superarcs[firstSupernode, lastSupernode)
529  transferTargetView // input view of transferTarget[firstSupernode, lastSupernode)
530  );
531  } // scope ComputeSuperarcTransferWeightsWorklet
532 
533  // 5. Now we need to sort the transfer targets into contiguous segments
534  {
535  // create view of superSortPermute[firstSupernode, lastSupernode) for sorting
537  superSortPermuteView(this->SuperSortPermute, firstSupernode, numSupernodesToProcess);
538  // create comperator for the sort
540  transferTargetComperator(this->TransferTarget);
541  // sort the subrange of our array
542  vtkm::cont::Algorithm::Sort(superSortPermuteView, transferTargetComperator);
543  }
544 
545  // 6. The [first,last] subrange is now permuted, so we can copy the transfer targets and weights into arrays
546  // The following code block implements the following for loop using fancy array handles and copy
547  // for (vtkm::Id supernode = firstSupernode; supernode < lastSupernode; supernode++)
548  // {
549  // sortedTransferTarget[supernode] = transferTarget[superSortPermute[supernode]];
550  // valuePrefixSum[supernode] = sweepValues[superSortPermute[supernode]];
551  // }
552  {
553  // copy transfer target in the sorted order
555  sortedTransferTargetView(this->SortedTransferTarget, firstSupernode, numSupernodesToProcess);
557  superSortPermuteView(this->SuperSortPermute, firstSupernode, numSupernodesToProcess);
558  auto permutedTransferTarget =
559  vtkm::cont::make_ArrayHandlePermutation(superSortPermuteView, // idArray
560  this->TransferTarget); // valueArray
561  vtkm::cont::Algorithm::Copy(permutedTransferTarget, sortedTransferTargetView);
562  // Note that any values associated with NO_SUCH_ELEMENT will be ignored
563  // copy transfer weight in the sorted order
565  valuePrefixSumView(this->ValuePrefixSum, firstSupernode, numSupernodesToProcess);
566  auto permutedDependentValues =
567  vtkm::cont::make_ArrayHandlePermutation(superSortPermuteView, // idArray
568  this->DependentValues); // valueArray
569  vtkm::cont::Algorithm::Copy(permutedDependentValues, valuePrefixSumView);
570  }
571 } // ComputeSuperarcTransferWeights()
572 
573 
574 // routine to transfer the weights
575 template <typename SweepValueType, typename ContourTreeFieldType>
577  vtkm::Id, // round, // Kept parameters in case we need it for debugging.
578  vtkm::Id, // iteration, // Kept parameters in case we need it for debugging.
579  vtkm::Id firstSupernode,
580  vtkm::Id lastSupernode)
581 { // TransferWeights()
582  // 7. Now perform a segmented prefix sum
583  vtkm::Id numSupernodesToProcess = lastSupernode - firstSupernode;
584  // Same as std::partial_sum(valuePrefixSum.begin() + firstSupernode, valuePrefixSum.begin() + lastSupernode, valuePrefixSum.begin() + firstSupernode);
585  {
586  // ValuePrefixSum[firstSuperNode, lastSupernode)
588  valuePrefixSumView(this->ValuePrefixSum, // subset ValuePrefixSum
589  firstSupernode, // start at firstSupernode
590  numSupernodesToProcess); // until lastSuperNode (not inclued)
591  // TODO: If it is safe to use the same array as input and output for ScanInclusive then this code should be updated to avoid the extra copy
592  // In this case our traget array is the same as our source array. For safety we
593  // store the values of our prefix sum in a temporary arrya and then copy the values
594  // back into our valuePrefixSumView at the end
596  tempScanInclusiveTarget.Allocate(numSupernodesToProcess);
597  // Compute the partial sum for DependentValues[firstSuperNode, lastSupernode) and write to ValuePrefixSum[firstSuperNode, lastSupernode)
598  vtkm::cont::Algorithm::ScanInclusive(valuePrefixSumView, // input
599  tempScanInclusiveTarget); // result of partial sum
600  // Now copy the values from our prefix sum back
601  vtkm::cont::Algorithm::Copy(tempScanInclusiveTarget, valuePrefixSumView);
602  }
603 
604  // 7a. and 7b.
605  {
606  // 7a. Find the RHE of each group and transfer the prefix sum weight
607  // Note that we do not compute the transfer weight separately, we add it in place instead
608  // Instantiate the worklet
609  auto supernodeIndex =
610  vtkm::cont::make_ArrayHandleCounting(firstSupernode, vtkm::Id{ 1 }, numSupernodesToProcess);
611  VTKM_ASSERT(firstSupernode + numSupernodesToProcess <=
612  this->ValuePrefixSum.GetNumberOfValues());
613  auto valuePrefixSumView = vtkm::cont::make_ArrayHandleView(
614  this->ValuePrefixSum, firstSupernode, numSupernodesToProcess);
615 
616  vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
617  TransferWeightsUpdateRHEWorklet transferWeightsUpdateRHEWorklet(lastSupernode);
618  // Invoke the worklet
619  this->Invoke(transferWeightsUpdateRHEWorklet, // worklet
620  supernodeIndex, // input counting array [firstSupernode, lastSupernode)
621  this->SortedTransferTarget,
622  valuePrefixSumView, // input view of valuePrefixSum[firstSupernode, lastSupernode)
623  this->DependentValues);
624  }
625 
626  {
627  VTKM_ASSERT(firstSupernode + 1 + numSupernodesToProcess - 1 <=
628  this->SortedTransferTarget.GetNumberOfValues());
629  auto sortedTransferTargetView = vtkm::cont::make_ArrayHandleView(
630  this->SortedTransferTarget, firstSupernode + 1, numSupernodesToProcess - 1);
631  VTKM_ASSERT(firstSupernode + 1 + numSupernodesToProcess - 1 <=
632  this->SortedTransferTarget.GetNumberOfValues());
633  auto sortedTransferTargetShiftedView = vtkm::cont::make_ArrayHandleView(
634  this->SortedTransferTarget, firstSupernode, numSupernodesToProcess - 1);
635  auto valuePrefixSumPreviousValueView = vtkm::cont::make_ArrayHandleView(
636  this->ValuePrefixSum, firstSupernode, numSupernodesToProcess - 1);
637 
638  // 7b. Now find the LHE of each group and subtract out the prior weight
639  vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::
640  TransferWeightsUpdateLHEWorklet transferWeightsUpdateLHEWorklet;
641  this->Invoke(transferWeightsUpdateLHEWorklet,
642  sortedTransferTargetView,
643  sortedTransferTargetShiftedView,
644  valuePrefixSumPreviousValueView,
645  this->DependentValues);
646  }
647 } // TransferWeights()
648 
649 
650 // debug routine
651 template <typename SweepValueType, typename ContourTreeFieldType>
653  std::string message,
654  const char* fileName,
655  long lineNum) const
656 { // DebugPrint()
657  std::stringstream resultStream;
658  resultStream << std::endl;
659  resultStream << "----------------------------------------" << std::endl;
660  resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
661  << lineNum << std::endl;
662  resultStream << std::left << message << std::endl;
663  resultStream << "Hypersweep Value Array Contains: " << std::endl;
664  resultStream << "----------------------------------------" << std::endl;
665  resultStream << std::endl;
666 
667  vtkm::worklet::contourtree_augmented::PrintHeader(this->DependentValues.GetNumberOfValues(),
668  resultStream);
670  "Intrinsic", this->IntrinsicValues, -1, resultStream);
672  "Dependent", this->DependentValues, -1, resultStream);
674  "Prefix Sum", this->ValuePrefixSum, -1, resultStream);
676  "Transfer To", this->TransferTarget, -1, resultStream);
678  "Sorted Transfer", this->SortedTransferTarget, -1, resultStream);
680  "Sort Permute", this->SuperSortPermute, -1, resultStream);
681  return resultStream.str();
682 } // DebugPrint()
683 
684 
685 // Routine to save the hierarchical tree to file
686 template <typename SweepValueType, typename ContourTreeFieldType>
688  std::string message,
689  const char* outFileName) const
690 { // SaveHierarchicalContourTreeDot()
691  std::string hierarchicalTreeDotString =
692  HierarchicalContourTreeDotGraphPrint<vtkm::worklet::contourtree_augmented::IdArrayType>(
693  message,
694  this->HierarchicalTree,
696  SHOW_ALL_HYPERIDS | SHOW_EXTRA_DATA, //|GV_NODE_NAME_USES_GLOBAL_ID
697  this->BlockId,
698  this->DependentValues);
699  std::ofstream hierarchicalTreeFile(outFileName);
700  hierarchicalTreeFile << hierarchicalTreeDotString;
701 } // SaveHierarchicalContourTreeDot
702 
703 
704 } // namespace contourtree_distributed
705 } // namespace worklet
706 } // namespace vtkm
707 
708 #endif
vtkm::worklet::contourtree_distributed::HierarchicalContourTree::Superparents
vtkm::worklet::contourtree_augmented::IdArrayType Superparents
Definition: HierarchicalContourTree.h:120
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::worklet::contourtree_distributed::HierarchicalContourTree< ContourTreeFieldType >
vtkm::cont::ArrayHandle< SweepValueType >
ComputeSuperarcTransferWeightsWorklet.h
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::SaveHierarchicalContourTreeDot
void SaveHierarchicalContourTreeDot(std::string message, const char *outFileName) const
Routine to save the HierarchicalContourTree of this HierarchicalHyperSweeper to a Dot file.
Definition: HierarchicalHyperSweeper.h:687
vtkm::cont::Algorithm::ScanInclusive
static VTKM_CONT T ScanInclusive(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::cont::ArrayHandle< T, COut > &output)
Definition: Algorithm.h:731
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::Invoke
vtkm::cont::Invoker Invoke
Used internally to Invoke worklets.
Definition: HierarchicalHyperSweeper.h:200
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::InitializeIntrinsicVertexCount
void InitializeIntrinsicVertexCount(const HierarchicalContourTree< ContourTreeFieldType > &hierarchicalTree, const MeshType &baseBlock, const vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler &localToGlobalIdRelabeler, vtkm::worklet::contourtree_augmented::IdArrayType &superarcRegularCounts)
Our routines to initialize the sweep need to be static (or externa)l if we are going to use the const...
Definition: HierarchicalHyperSweeper.h:232
HierarchicalContourTree.h
vtkm::cont::make_ArrayHandleView
ArrayHandleView< ArrayHandleType > make_ArrayHandleView(const ArrayHandleType &array, vtkm::Id startIndex, vtkm::Id numValues)
Definition: ArrayHandleView.h:222
vtkm::worklet::contourtree_distributed::SHOW_ALL_HYPERIDS
constexpr vtkm::Id SHOW_ALL_HYPERIDS
Definition: PrintGraph.h:235
VTKM_ASSERT
#define VTKM_ASSERT(condition)
Definition: Assert.h:43
vtkm::cont::ArrayHandle::Allocate
VTKM_CONT void Allocate(vtkm::Id numberOfValues, vtkm::CopyFlag preserve, vtkm::cont::Token &token) const
Allocates an array large enough to hold the given number of values.
Definition: ArrayHandle.h:465
vtkm::cont::ArrayHandle::AllocateAndFill
VTKM_CONT void AllocateAndFill(vtkm::Id numberOfValues, const ValueType &fillValue, vtkm::CopyFlag preserve, vtkm::cont::Token &token) const
Allocates an array and fills it with an initial value.
Definition: ArrayHandle.h:495
vtkm::cont::make_ArrayHandleCounting
VTKM_CONT vtkm::cont::ArrayHandleCounting< CountingValueType > make_ArrayHandleCounting(CountingValueType start, CountingValueType step, vtkm::Id length)
A convenience function for creating an ArrayHandleCounting.
Definition: ArrayHandleCounting.h:151
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::LocalHyperSweep
void LocalHyperSweep()
routine to do the local hypersweep using addition / subtraction The funtion use the ComputeSuperarcDe...
Definition: HierarchicalHyperSweeper.h:324
vtkm::cont::ArrayHandleView
Definition: ArrayHandleView.h:187
vtkm::cont::Algorithm::Sort
static VTKM_CONT void Sort(vtkm::cont::DeviceAdapterId devId, vtkm::cont::ArrayHandle< T, Storage > &values)
Definition: Algorithm.h:965
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::DependentValues
const vtkm::cont::ArrayHandle< SweepValueType > & DependentValues
Definition: HierarchicalHyperSweeper.h:120
vtkm::cont::Algorithm::Copy
static VTKM_CONT bool Copy(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::cont::ArrayHandle< U, COut > &output)
Definition: Algorithm.h:410
PrintVectors.h
vtkm::worklet::contourtree_distributed::SHOW_EXTRA_DATA
constexpr vtkm::Id SHOW_EXTRA_DATA
Definition: PrintGraph.h:181
vtkm::worklet::contourtree_distributed::HierarchicalContourTree::GetFindRegularByGlobal
VTKM_CONT FindRegularByGlobal GetFindRegularByGlobal() const
routine to create a FindRegularByGlobal object that we can use as an input for worklets to call the f...
Definition: HierarchicalContourTree.h:174
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::IntrinsicValues
const vtkm::cont::ArrayHandle< SweepValueType > & IntrinsicValues
Definition: HierarchicalHyperSweeper.h:118
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
InitializeIntrinsicVertexCountComputeSuperparentIdsWorklet.h
vtkm::worklet::contourtree_distributed::SHOW_ALL_SUPERIDS
constexpr vtkm::Id SHOW_ALL_SUPERIDS
Definition: PrintGraph.h:232
TransferTargetComperator.h
vtkm::cont::LogLevel::Info
@ Info
Information messages (detected hardware, etc) and temporary debugging output.
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::DebugPrint
std::string DebugPrint(std::string message, const char *fileName, long lineNum) const
Debug routine to print contents of the HiearchicalHyperSweep.
Definition: HierarchicalHyperSweeper.h:652
IdRelabeler.h
vtkm::cont::ArrayHandleCounting< vtkm::Id >
vtkm::cont::Invoker
Allows launching any worklet without a dispatcher.
Definition: Invoker.h:41
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::HierarchicalTree
const HierarchicalContourTree< ContourTreeFieldType > & HierarchicalTree
Definition: HierarchicalHyperSweeper.h:110
Types.h
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper
Definition: ComputeSuperarcDependentWeightsWorklet.h:59
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::ComputeSuperarcDependentWeights
void ComputeSuperarcDependentWeights(vtkm::Id round, vtkm::Id iteration, vtkm::Id firstSupernode, vtkm::Id lastSupernode)
Routine to compute the correct weights dependent on each superarc in a subrange (defined by the round...
Definition: HierarchicalHyperSweeper.h:421
vtkm::worklet::contourtree_distributed::SHOW_SUPER_STRUCTURE
constexpr vtkm::Id SHOW_SUPER_STRUCTURE
Definition: PrintGraph.h:166
PrintGraph.h
vtkm::worklet::contourtree_distributed::hierarchical_hyper_sweeper::TransferTargetComperator
Definition: TransferTargetComperator.h:116
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::SortedTransferTarget
vtkm::worklet::contourtree_augmented::IdArrayType SortedTransferTarget
Definition: HierarchicalHyperSweeper.h:132
vtkm::worklet::contourtree_augmented::mesh_dem::IdRelabeler
A utility class that converts Ids from local to global given a mesh.
Definition: IdRelabeler.h:79
InitializeIntrinsicVertexCountSubtractLowEndWorklet.h
VTKM_LOG_S
#define VTKM_LOG_S(level,...)
Writes a message using stream syntax to the indicated log level.
Definition: Logging.h:261
vtkm::cont::make_ArrayHandlePermutation
VTKM_CONT vtkm::cont::ArrayHandlePermutation< IndexArrayHandleType, ValueArrayHandleType > make_ArrayHandlePermutation(IndexArrayHandleType indexArray, ValueArrayHandleType valueArray)
make_ArrayHandleTransform is convenience function to generate an ArrayHandleTransform.
Definition: ArrayHandlePermutation.h:279
TransferWeightsUpdateLHEWorklet.h
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::ValuePrefixSum
vtkm::cont::ArrayHandle< SweepValueType > ValuePrefixSum
Definition: HierarchicalHyperSweeper.h:129
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::SuperSortPermute
vtkm::worklet::contourtree_augmented::IdArrayType SuperSortPermute
Definition: HierarchicalHyperSweeper.h:134
ComputeSuperarcDependentWeightsWorklet.h
vtkm::worklet::contourtree_distributed::HierarchicalContourTree::Regular2Supernode
vtkm::worklet::contourtree_augmented::IdArrayType Regular2Supernode
Definition: HierarchicalContourTree.h:118
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::NumOwnedRegularVertices
vtkm::Id NumOwnedRegularVertices
Definition: HierarchicalHyperSweeper.h:123
vtkm::worklet::contourtree_distributed::SHOW_HYPER_STRUCTURE
constexpr vtkm::Id SHOW_HYPER_STRUCTURE
Definition: PrintGraph.h:167
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::HierarchicalHyperSweeper
HierarchicalHyperSweeper(vtkm::Id blockId, const HierarchicalContourTree< ContourTreeFieldType > &hierarchicalTree, const vtkm::cont::ArrayHandle< SweepValueType > &intrinsicValues, const vtkm::cont::ArrayHandle< SweepValueType > &dependentValues)
Constructor.
Definition: HierarchicalHyperSweeper.h:206
vtkm::worklet::contourtree_augmented::PrintIndices
void PrintIndices(std::string label, const vtkm::cont::ArrayHandle< T > &iVec, vtkm::Id nIndices=-1, std::ostream &outStream=std::cout)
Definition: augmented/PrintVectors.h:253
vtkm::worklet::contourtree_augmented::PrintHeader
void PrintHeader(vtkm::Id howMany, std::ostream &outStream=std::cout)
Definition: augmented/PrintVectors.h:151
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper
Definition: HierarchicalHyperSweeper.h:106
InitializeIntrinsicVertexCountInitalizeCountsWorklet.h
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::BlockId
vtkm::Id BlockId
Definition: HierarchicalHyperSweeper.h:113
TransferWeightsUpdateRHEWorklet.h
vtkm::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:54
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::TransferTarget
vtkm::worklet::contourtree_augmented::IdArrayType TransferTarget
Definition: HierarchicalHyperSweeper.h:131
vtkm::worklet::contourtree_distributed::SHOW_ALL_IDS
constexpr vtkm::Id SHOW_ALL_IDS
Definition: PrintGraph.h:228
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::TransferWeights
void TransferWeights(vtkm::Id round, vtkm::Id iteration, vtkm::Id firstSupernode, vtkm::Id lastSupernode)
routine to transfer the weights
Definition: HierarchicalHyperSweeper.h:576
vtkm::worklet::contourtree_distributed::HierarchicalHyperSweeper::ComputeSuperarcTransferWeights
void ComputeSuperarcTransferWeights(vtkm::Id round, vtkm::Id iteration, vtkm::Id firstSupernode, vtkm::Id lastSupernode)
routine to compute the weights to transfer to superarcs (defined by the round & iteration)
Definition: HierarchicalHyperSweeper.h:492