VTK-m  2.0
HierarchicalVolumetricBranchDecomposer.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 // HierarchicalVolumetricBranchDecomposer.h
49 //
50 //=======================================================================================
51 //
52 // COMMENTS:
53 //
54 // This class computes the branch decomposition by volume for a given hierarchical
55 // contour tree.
56 //
57 // It takes as input arrays of dependent and intrinsic volumes for each superarc
58 // (it needs both, in order to compute the dependent volume at each end of each superarc)
59 //
60 // Recall from the non-hierarchical version that in order to compute the branch decomposition,
61 // we need to choose the "best up" and "best down" superarc for each supernode - i.e. the
62 // superarc with the largest dependent volume. Since we only wish to compare superarcs that
63 // meet at a given supernode, we tiebreak by always taking the superarc whose "other" end
64 // has a higher ID.
65 //
66 // Once the best up & best down have been found for each supernode, branches are identified
67 // with (essentially) a graph connectivity computation.
68 //
69 // Conceptually, each superarc is a vertex in a new (temporary) graph. For each supernode, the
70 // "best up" superarc is connected to the "best down" superarc. This defines a graph in which
71 // each branch is a connected component. A single path-doubling pass then collects the branches
72 //
73 // In the non-hierarchical version, this was done with supernode IDs (I can't remember why),
74 // with the upper end of each branch being treated as the root node.
75 //
76 // To construct the hierarchical branch decomposition, we assume that the hierarchical contour
77 // tree has already been augmented with all attachment points. If not, the code may produce
78 // undefined results.
79 //
80 // In the first step, we will run a local routine for each rank to determine the best up / down
81 // as far as the rank knows. We will then do a fan-in swap to determine the best up / down for
82 // shared vertices. At the end of this step, all ranks will share the knowledge of the best
83 // up / down superarc, stored as:
84 // i. the superarc ID, which may be reused on other ranks
85 // ii. the global ID of the outer end of that superarc, which is unique across all ranks
86 // iii. the volume dependent on that superarc
87 //
88 // In the second stage, each rank will do a local computation of the branches. However, most ranks
89 // will not have the full set of supernodes / superarcs for each branch, even (or especially)
90 // for the master branch. It is therefore a bad idea to collapse to the upper end of the branch
91 // as we did in the non-hierarchical version.
92 //
93 // Instead, we will define the root of each component to be the most senior superarc ID. This will
94 // be canonical, because of the way we construct the hierarchical tree, with low superarc IDs
95 // occurring at higher levels of the tree, so all shared superarcs are a prefix set. Therefore,
96 // the most senior superarc ID will always indicate the highest level of the tree through which the
97 // branch passes, and is safe. Moreover, it is not necessary for each rank to determine the full
98 // branch, merely the part of the branch that passes through the superarcs it tracks. It may even
99 // happen that no single rank stores the entire branch, as for example if the global minimum
100 // and maximum are interior to different ranks.
101 //
102 // Note that most senior means testing iteration, round, then ID
103 //
104 // RESIZE SEMANTICS: Oliver Ruebel has asked for the semantics of all resize() calls to be annotated
105 // in order to ease porting to vtkm. These will be flagged with a RESIZE SEMANTICS: comment, and will
106 // generally fall into several patterns:
107 // 1. FIXED: Resize() is used to initialize the array size for an array that will never change size
108 // 2. COMPRESS: Resize() is used after a compression operation (eg remove_if()) so that the
109 // array size() call does not include the elements removed. This is a standard
110 // C++ pattern, but could be avoided by storing an explicit element count (curiously,
111 // the std::vector class does exactly this with logical vs. physical array sizes).
112 // 3. MULTI-COMPRESS: Resize() may also be used (as in the early stages of the PPP algorithm) to give
113 // a collapsing array size of working elements. Again, this could on principle by
114 // avoided with an array count, but is likely to be intricate.
115 //
116 //=======================================================================================
117 
118 
119 #ifndef vtk_m_filter_scalar_topology_worklet_HierarchicalVolumetricBranchDecomposer_h
120 #define vtk_m_filter_scalar_topology_worklet_HierarchicalVolumetricBranchDecomposer_h
121 
122 #include <iomanip>
123 #include <string>
124 
125 // Contour tree includes, not yet moved into new filter structure
129 
130 // Worklets
140 
141 #ifdef DEBUG_PRINT
142 #define DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
143 #endif
144 
145 namespace vtkm
146 {
147 namespace filter
148 {
149 namespace scalar_topology
150 {
151 
154 { // class HierarchicalVolumetricBranchDecomposer
155 public:
162 
166 
194  void LocalBestUpDownByVolume(const vtkm::cont::DataSet& hierarchicalTreeDataSet,
195  const vtkm::cont::ArrayHandle<vtkm::Id>& intrinsicValues,
196  const vtkm::cont::ArrayHandle<vtkm::Id>& dependentValues,
197  vtkm::Id totalVolume);
198 
200  void CollapseBranches(const vtkm::cont::DataSet& hierarchicalTreeDataSet,
202 
204  template <typename IdArrayHandleType, typename DataValueArrayHandleType>
205  static std::string PrintBranches(const IdArrayHandleType& hierarchicalTreeSuperarcsAH,
206  const IdArrayHandleType& hierarchicalTreeSupernodesAH,
207  const IdArrayHandleType& hierarchicalTreeRegularNodeGlobalIdsAH,
208  const DataValueArrayHandleType& hierarchicalTreeDataValuesAH,
209  const IdArrayHandleType& branchRootAH);
210  static std::string PrintBranches(const vtkm::cont::DataSet& ds);
211 
213  std::string DebugPrint(std::string message, const char* fileName, long lineNum);
214 
215 private:
218 
219 }; // class HierarchicalVolumetricBranchDecomposer
220 
221 
223  const vtkm::cont::DataSet& hierarchicalTreeDataSet,
224  const vtkm::cont::ArrayHandle<vtkm::Id>& intrinsicValues,
225  const vtkm::cont::ArrayHandle<vtkm::Id>& dependentValues,
226  vtkm::Id totalVolume)
227 {
228  // Get required arrays for hierarchical tree form data set
229  auto hierarchicalTreeSupernodes = hierarchicalTreeDataSet.GetField("Supernodes")
230  .GetData()
232  auto hierarchicalTreeSuperarcs = hierarchicalTreeDataSet.GetField("Superarcs")
233  .GetData()
235  auto hierarchicalTreeRegularNodeGlobalIds =
236  hierarchicalTreeDataSet.GetField("RegularNodeGlobalIds")
237  .GetData()
239 
240  // LocalBestUpDownByVolume
241  // STAGE I: Allocate memory for our arrays
242  vtkm::Id nSupernodes = hierarchicalTreeSupernodes.GetNumberOfValues();
243  // WARNING: This differs from the non-hierarchical version by using the full size *WITH* virtual superarcs
244  vtkm::Id nSuperarcs = hierarchicalTreeSuperarcs.GetNumberOfValues();
245 
246  // set up a list of superarcs as Edges for reference in our comparator
248  superarcList.Allocate(nSuperarcs);
250  LocalBestUpDownByVolumeInitSuperarcListWorklet{}, // the worklet
251  hierarchicalTreeSuperarcs, // input
252  superarcList // output
253  );
254 
255 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
256  {
257  std::stringstream resultStream;
259  resultStream);
261  "Superarc List", superarcList, -1, resultStream);
262  resultStream << std::endl;
263  VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
264  }
265 #endif
266 
267  // create a list of the non-virtual superarcs
269  // and fill it up with index values [0, 1, 2 ... nSuperarcs-1] while simultaneously stream compacting the
270  // values by keeping only those indices where the hierarchicalTree->Superarcs is not NoSuchElement.
272  hierarchicalTreeSuperarcs, // stencil
273  actualSuperarcs, // output target array
275  // NOTE: The behavior here is slightly different from the original implementation, as the original code
276  // here does not resize actualSuperarcs but keeps it at the full length of nSuperacs and instead
277  // relies on the nActualSuperarcs parameter. However, the extra values are never used, so compacting
278  // the array here should be fine.
279  vtkm::Id nActualSuperarcs = actualSuperarcs.GetNumberOfValues();
280 
281 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
282  {
283  std::stringstream resultStream;
284  vtkm::worklet::contourtree_augmented::PrintHeader(nActualSuperarcs, resultStream);
286  "Actual Superarcs", actualSuperarcs, -1, resultStream);
287  resultStream << std::endl;
288  VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
289  }
290 #endif
291 
292  // and set up arrays for the best upwards, downwards superarcs at each supernode
293  // initialize everything to NO_SUCH_ELEMENT for safety (we will test against this, so it's necessary)
294  // Set up temporary constant arrays for each group of arrays and initalize the arrays
295  // Initalize the arrays
297  this->UpVolume.AllocateAndFill(nSuperarcs, 0);
298  this->DownVolume.AllocateAndFill(nSuperarcs, 0);
299  this->BestUpSupernode.AllocateAndFill(nSupernodes, NO_SUCH_ELEMENT);
301  this->BestUpVolume.AllocateAndFill(nSupernodes, 0);
302  this->BestDownVolume.AllocateAndFill(nSupernodes, 0);
303 
304 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
305  VTKM_LOG_S(vtkm::cont::LogLevel::Info, DebugPrint("Arrays Allocated", __FILE__, __LINE__));
306 #endif
307 
308  // STAGE II: Pick the best (largest volume) edge upwards and downwards
309  // II A. Compute the up / down volumes for indirect sorting
310  // this is the same in spirit as ContourTreeMaker::ComputeVolumeBranchDecomposition() STAGE II A.
311  // given that we have already suppressed the non-virtual superarcs
312  // however, in this case, we need to use the actualSuperarcs array instead of the main array
313  {
314  vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer::
315  LocalBestUpDownByVolumeBestUpDownEdgeWorklet bestUpDownEdgeWorklet(totalVolume);
316  // permut input and output arrays here so we can use FieldIn and FieldOut to
317  // avoid the use of WholeArray access in the worklet
318  auto permutedHierarchicalTreeSuperarcs =
319  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, hierarchicalTreeSuperarcs); // input
320  auto permutedDependetValues =
321  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, dependentValues); // input
322  auto permutedIntrinsicValues =
323  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, intrinsicValues); // input
324  auto permutedUpVolume =
325  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, this->UpVolume); // output
326  auto permitedDownVolume =
327  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, this->DownVolume); // outout
328 
329  this->Invoke(bestUpDownEdgeWorklet, // the worklet
330  permutedHierarchicalTreeSuperarcs, // input
331  permutedDependetValues, // input
332  permutedIntrinsicValues, // input
333  permutedUpVolume, // output
334  permitedDownVolume // outout
335  );
336  }
337 
338 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
339  VTKM_LOG_S(vtkm::cont::LogLevel::Info, DebugPrint("Volume Arrays Set Up", __FILE__, __LINE__));
340  {
341  std::stringstream resultStream;
343  resultStream);
345  "Superarc List", superarcList, -1, resultStream);
346  resultStream << std::endl;
347  VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
348  }
349 #endif
350  // II B. Pick the best downwards volume by sorting on upper vertex then processing by segments (segmented by vertex)
351  // II B 1. Sort the superarcs by upper vertex
352  // NB: We reuse the actual superarcs list here - this works because we have indexed the volumes on the underlying superarc ID
353  // NB 2: Notice that we only sort the "actual" ones - this is to avoid unnecessary resize() calls in vtkm later on
354  {
355  vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer::
356  SuperArcVolumetricComparatorIndirectGlobalIdComparator
357  SuperArcVolumetricComparatorIndirectGlobalIdComparator(
358  this->UpVolume, superarcList, hierarchicalTreeRegularNodeGlobalIds, false);
359  vtkm::cont::Algorithm::Sort(actualSuperarcs,
360  SuperArcVolumetricComparatorIndirectGlobalIdComparator);
361  }
362 
363 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
364  {
365  std::stringstream resultStream;
366  resultStream
367  << "Actual Superarc List After Sorting By High End (Full Array, including ignored elements)"
368  << std::endl;
369  vtkm::worklet::contourtree_augmented::PrintHeader(nActualSuperarcs, resultStream);
371  "Actual Superarcs", actualSuperarcs, -1, resultStream);
372  resultStream << std::endl;
373  VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
374  }
375 #endif
376  // II B 2. Per vertex, best superarc writes to the best downward array
377  {
378  auto permutedUpVolume =
379  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, this->UpVolume);
381  LocalBestUpDownByVolumeWorklet<true>{ nActualSuperarcs },
382  actualSuperarcs, // input
383  superarcList, // input
384  permutedUpVolume, // input
385  hierarchicalTreeRegularNodeGlobalIds, // input
386  hierarchicalTreeSupernodes, // input
387  this->BestDownSupernode, // output
388  this->BestDownVolume // output
389  );
390  }
391 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
393  DebugPrint("BestDownSupernode Written", __FILE__, __LINE__));
394 #endif
395 
396  // II B 3. Repeat for lower vertex
397  {
398  vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer::
399  SuperArcVolumetricComparatorIndirectGlobalIdComparator
400  SuperArcVolumetricComparatorIndirectGlobalIdComparator(
401  this->DownVolume, superarcList, hierarchicalTreeRegularNodeGlobalIds, true);
402  vtkm::cont::Algorithm::Sort(actualSuperarcs,
403  SuperArcVolumetricComparatorIndirectGlobalIdComparator);
404  }
405 
406 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
407  {
408  std::stringstream resultStream;
409  resultStream
410  << "Actual Superarc List After Sorting By Low End (Full Array, including ignored elements)"
411  << std::endl;
412  vtkm::worklet::contourtree_augmented::PrintHeader(nActualSuperarcs, resultStream);
414  "Actual Superarcs", actualSuperarcs, -1, resultStream);
415  resultStream << std::endl;
416  VTKM_LOG_S(vtkm::cont::LogLevel::Info, resultStream.str());
417  }
418 #endif
419 
420  // II B 2. Per vertex, best superarc writes to the best upward array
421  {
422  auto permutedDownVolume =
423  vtkm::cont::make_ArrayHandlePermutation(actualSuperarcs, this->DownVolume);
425  LocalBestUpDownByVolumeWorklet<false>{ nActualSuperarcs },
426  actualSuperarcs, // input
427  superarcList, // input
428  permutedDownVolume, // input
429  hierarchicalTreeRegularNodeGlobalIds, // input
430  hierarchicalTreeSupernodes, // input
431  this->BestUpSupernode, // output
432  this->BestUpVolume // output
433  );
434  }
435 
436 #ifdef DEBUG_HIERARCHICAL_VOLUMETRIC_BRANCH_DECOMPOSER
438  DebugPrint("Local Best Up/Down Computed", __FILE__, __LINE__));
439 #endif
440 } // LocalBestUpDownByVolume
441 
442 
444  const vtkm::cont::DataSet& hierarchicalTreeDataSet,
446 { // CollapseBranches
447  // Get required arrays for hierarchical tree form data set
448  auto hierarchicalTreeSupernodes = hierarchicalTreeDataSet.GetField("Supernodes")
449  .GetData()
451  auto hierarchicalTreeSuperarcs = hierarchicalTreeDataSet.GetField("Superarcs")
452  .GetData()
454  auto hierarchicalTreeRegularNodeGlobalIds =
455  hierarchicalTreeDataSet.GetField("RegularNodeGlobalIds")
456  .GetData()
458  auto hierarchicalTreeRegularNodeSortOrder =
459  hierarchicalTreeDataSet.GetField("RegularNodeSortOrder")
460  .GetData()
462  auto hierarchicalTreeRegular2Supernode = hierarchicalTreeDataSet.GetField("Regular2Supernode")
463  .GetData()
465  auto hierarchicalTreeWhichRound = hierarchicalTreeDataSet.GetField("WhichRound")
466  .GetData()
468 
469  // initialise the superarcs to be their own branch roots
471 
472  // For each supernode, convert the best up into a superarc ID
473  {
475  hierarchicalTreeRegularNodeSortOrder, hierarchicalTreeRegularNodeGlobalIds
476  };
478  hierarchicalTreeSuperarcs
479  };
480 
481  using vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer::
482  CollapseBranchesWorklet;
483  this->Invoke(CollapseBranchesWorklet{}, // the worklet
484  this->BestUpSupernode, // input
485  this->BestDownSupernode, // input
486  findRegularByGlobal, // input ExecutionObject
487  findSuperArcBetweenNodes, // input ExecutionObject
488  hierarchicalTreeRegular2Supernode, // input
489  hierarchicalTreeWhichRound, // input
490  branchRoot);
491  }
492 
493  // OK. We've now initialized it, and can use pointer-doubling
494  // Compute the number of log steps required
495  vtkm::Id nLogSteps = 1;
496  for (vtkm::Id shifter = branchRoot.GetNumberOfValues(); shifter != 0; shifter >>= 1)
497  {
498  nLogSteps++;
499  }
500 
501  // loop that many times, pointer-doubling
502  for (vtkm::Id iteration = 0; iteration < nLogSteps; iteration++)
503  { // per iteration
504  // loop through the vertices, updating
505  using vtkm::filter::scalar_topology::hierarchical_volumetric_branch_decomposer::
506  CollapseBranchesPointerDoublingWorklet;
507  this->Invoke(CollapseBranchesPointerDoublingWorklet{}, branchRoot);
508  } // per iteration
509 } // CollapseBranches
510 
511 
512 // PrintBranches
513 // we want to dump out the branches as viewed by this rank.
514 // most of the processing will be external, so we keep this simple.
515 // For each end of the superarc, we print out value & global ID prefixed by global ID of the branch root
516 // The external processing will then sort them to construct segments (as usual) in the array
517 // then a post-process can find the first and last in each segment & print out the branch
518 // In order for the sort to work lexicographically, we need to print out in the following order:
519 // I Branch Root Global ID
520 // II Supernode Value
521 // III Supernode Global ID
522 
523 // Note the following is a template to be called via cast-and-call
524 template <typename IdArrayHandleType, typename DataValueArrayHandleType>
526  const IdArrayHandleType& hierarchicalTreeSuperarcsAH,
527  const IdArrayHandleType& hierarchicalTreeSupernodesAH,
528  const IdArrayHandleType& hierarchicalTreeRegularNodeGlobalIdsAH,
529  const DataValueArrayHandleType& hierarchicalTreeDataValuesAH,
530  const IdArrayHandleType& branchRootAH)
531 {
532  auto hierarchicalTreeSuperarcsPortal = hierarchicalTreeSuperarcsAH.ReadPortal();
533  vtkm::Id nSuperarcs = hierarchicalTreeSuperarcsAH.GetNumberOfValues();
534  auto hierarchicalTreeSupernodesPortal = hierarchicalTreeSupernodesAH.ReadPortal();
535  auto hierarchicalTreeRegularNodeGlobalIdsPortal =
536  hierarchicalTreeRegularNodeGlobalIdsAH.ReadPortal();
537  auto hierarchicalTreeDataValuesPortal = hierarchicalTreeDataValuesAH.ReadPortal();
538  auto branchRootPortal = branchRootAH.ReadPortal();
539 
540  std::stringstream resultStream;
541  // loop through the individual superarcs
542 
543  for (vtkm::Id superarc = 0; superarc < nSuperarcs; superarc++)
544  { // per superarc
545  // explicit test for root superarc / attachment points
547  hierarchicalTreeSuperarcsPortal.Get(superarc)))
548  {
549  continue;
550  }
551 
552  // now retrieve the branch root's global ID
553  vtkm::Id branchRootSuperId = branchRootPortal.Get(superarc);
554  vtkm::Id branchRootRegularId = hierarchicalTreeSupernodesPortal.Get(branchRootSuperId);
555  vtkm::Id branchRootGlobalId =
556  hierarchicalTreeRegularNodeGlobalIdsPortal.Get(branchRootRegularId);
557 
558  // now retrieve the global ID & value for each end & output them
559  vtkm::Id superFromRegularId = hierarchicalTreeSupernodesPortal.Get(superarc);
560  vtkm::Id superFromGlobalId = hierarchicalTreeRegularNodeGlobalIdsPortal.Get(superFromRegularId);
561  typename DataValueArrayHandleType::ValueType superFromValue =
562  hierarchicalTreeDataValuesPortal.Get(superFromRegularId);
563  resultStream << branchRootGlobalId << "\t" << superFromValue << "\t" << superFromGlobalId
564  << std::endl;
565 
566  // now retrieve the global ID & value for each end & output them
568  hierarchicalTreeSuperarcsPortal.Get(superarc));
569  vtkm::Id superToGlobalId = hierarchicalTreeRegularNodeGlobalIdsPortal.Get(superToRegularId);
570  typename DataValueArrayHandleType::ValueType superToValue =
571  hierarchicalTreeDataValuesPortal.Get(superToRegularId);
572  resultStream << branchRootGlobalId << "\t" << superToValue << "\t" << superToGlobalId
573  << std::endl;
574  } // per superarc
575 
576  return resultStream.str();
577 } // PrintBranches
578 
580  const vtkm::cont::DataSet& ds)
581 {
582  auto hierarchicalTreeSuperarcsAH =
584  auto hierarchicalTreeSupernodesAH =
586 
587  auto hierarchicalTreeRegularNodeGlobalIdsAH =
588  ds.GetField("RegularNodeGlobalIds")
589  .GetData()
591 
592  auto hierarchicalTreeDataValuesData = ds.GetField("DataValues").GetData();
593 
594  auto branchRootAH =
596 
597  std::string result;
598 
599  hierarchicalTreeDataValuesData.CastAndCallForTypes<TypeListScalarAll, VTKM_DEFAULT_STORAGE_LIST>(
600  [&](const auto& hierarchicalTreeDataValuesAH) {
601  result = PrintBranches(hierarchicalTreeSuperarcsAH,
602  hierarchicalTreeSupernodesAH,
603  hierarchicalTreeRegularNodeGlobalIdsAH,
604  hierarchicalTreeDataValuesAH,
605  branchRootAH);
606  });
607 
608  return result;
609 } // PrintBranches
610 
611 
612 // debug routine
613 inline std::string HierarchicalVolumetricBranchDecomposer::DebugPrint(std::string message,
614  const char* fileName,
615  long lineNum)
616 { // DebugPrint()
617  std::stringstream resultStream;
618  resultStream << "----------------------------------------" << std::endl;
619  resultStream << std::setw(30) << std::left << fileName << ":" << std::right << std::setw(4)
620  << lineNum << std::endl;
621  resultStream << std::left << message << std::endl;
622  resultStream << "Hypersweep Value Array Contains: " << std::endl;
623  resultStream << "----------------------------------------" << std::endl;
624  resultStream << std::endl;
625 
627  resultStream);
629  "Up Volume by SA", this->UpVolume, -1, resultStream);
631  "Down Volume by SA", this->DownVolume, -1, resultStream);
633  "Best Down Snode by SN", this->BestDownSupernode, -1, resultStream);
635  "Best Down Volume by SN", this->BestDownVolume, -1, resultStream);
637  "Best Up Snode by SN", this->BestUpSupernode, -1, resultStream);
639  "Best Up Volume by SN", this->BestUpVolume, -1, resultStream);
640  std::cout << std::endl;
641  return resultStream.str();
642 } // DebugPrint()
643 
644 } // namespace scalar_topology
645 } // namespace filter
646 } // namespace vtkm
647 
648 
649 #endif
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::PrintBranches
static std::string PrintBranches(const IdArrayHandleType &hierarchicalTreeSuperarcsAH, const IdArrayHandleType &hierarchicalTreeSupernodesAH, const IdArrayHandleType &hierarchicalTreeRegularNodeGlobalIdsAH, const DataValueArrayHandleType &hierarchicalTreeDataValuesAH, const IdArrayHandleType &branchRootAH)
routines to print branches
Definition: HierarchicalVolumetricBranchDecomposer.h:525
vtkm::cont::ArrayHandle< vtkm::Id >
vtkm::cont::UnknownArrayHandle::AsArrayHandle
VTKM_CONT void AsArrayHandle(vtkm::cont::ArrayHandle< T, S > &array) const
Definition: UnknownArrayHandle.h:616
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::DownVolume
vtkm::worklet::contourtree_augmented::IdArrayType DownVolume
Definition: HierarchicalVolumetricBranchDecomposer.h:165
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
SuperArcVolumetricComparatorIndirectGlobalIdComparator.h
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
LocalBestUpDownByVolumeInitSuperarcListWorklet.h
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
CollapseBranchesPointerDoublingWorklet.h
FindRegularByGlobal.h
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::Invoke
vtkm::cont::Invoker Invoke
Used internally to Invoke worklets.
Definition: HierarchicalVolumetricBranchDecomposer.h:217
vtkm::cont::DataSet
Definition: DataSet.h:34
vtkm::cont::Algorithm::Sort
static VTKM_CONT void Sort(vtkm::cont::DeviceAdapterId devId, vtkm::cont::ArrayHandle< T, Storage > &values)
Definition: Algorithm.h:965
vtkm::TypeListScalarAll
vtkm::List< vtkm::Int8, vtkm::UInt8, vtkm::Int16, vtkm::UInt16, vtkm::Int32, vtkm::UInt32, vtkm::Int64, vtkm::UInt64, vtkm::Float32, vtkm::Float64 > TypeListScalarAll
A list of all scalars defined in vtkm/Types.h.
Definition: TypeList.h:105
PrintVectors.h
vtkm::worklet::contourtree_augmented::MaskedIndex
VTKM_EXEC_CONT vtkm::Id MaskedIndex(vtkm::Id flaggedIndex)
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:127
FindSuperArcBetweenNodes.h
LocalBestUpDownByVolumeBestUpDownEdgeWorklet.h
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
vtkm::cont::Field::GetData
const vtkm::cont::UnknownArrayHandle & GetData() const
vtkm::worklet::contourtree_augmented::NoSuchElement
VTKM_EXEC_CONT bool NoSuchElement(vtkm::Id flaggedIndex)
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:97
vtkm::cont::LogLevel::Info
@ Info
Information messages (detected hardware, etc) and temporary debugging output.
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::BestUpSupernode
vtkm::worklet::contourtree_augmented::IdArrayType BestUpSupernode
we will want arrays for swapping with our partners, holding the best up/down superarc & the correspon...
Definition: HierarchicalVolumetricBranchDecomposer.h:158
CollapseBranchesWorklet.h
vtkm::cont::Invoker
Allows launching any worklet without a dispatcher.
Definition: Invoker.h:41
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::BestUpVolume
vtkm::worklet::contourtree_augmented::IdArrayType BestUpVolume
Definition: HierarchicalVolumetricBranchDecomposer.h:160
vtkm::cont::ArrayCopy
void ArrayCopy(const SourceArrayType &source, DestArrayType &destination)
Does a deep copy from one array to another array.
Definition: ArrayCopy.h:142
vtkm::worklet::scalar_topology::hierarchical_volumetric_branch_decomposer
Definition: CollapseBranchesWorklet.h:58
vtkm::cont::Algorithm::CopyIf
static VTKM_CONT void CopyIf(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, const vtkm::cont::ArrayHandle< U, CStencil > &stencil, vtkm::cont::ArrayHandle< T, COut > &output)
Definition: Algorithm.h:435
Types.h
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::DebugPrint
std::string DebugPrint(std::string message, const char *fileName, long lineNum)
debug routine
Definition: HierarchicalVolumetricBranchDecomposer.h:613
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer
Facture class for augmenting the hierarchical contour tree to enable computations of measures,...
Definition: HierarchicalVolumetricBranchDecomposer.h:153
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::LocalBestUpDownByVolume
void LocalBestUpDownByVolume(const vtkm::cont::DataSet &hierarchicalTreeDataSet, const vtkm::cont::ArrayHandle< vtkm::Id > &intrinsicValues, const vtkm::cont::ArrayHandle< vtkm::Id > &dependentValues, vtkm::Id totalVolume)
routines to compute branch decomposition by volume WARNING: we now have two types of hierarchical tre...
Definition: HierarchicalVolumetricBranchDecomposer.h:222
vtkm::worklet::contourtree_distributed::FindSuperArcBetweenNodes
ExecutionObject to generate a device object to use FindSuperArcBetweenNodes for the HierarchicalConto...
Definition: FindSuperArcBetweenNodes.h:116
LocalBestUpDownByVolumeWorklet.h
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::BestDownSupernode
vtkm::worklet::contourtree_augmented::IdArrayType BestDownSupernode
Definition: HierarchicalVolumetricBranchDecomposer.h:159
PrintGraph.h
NotNoSuchElementPredicate.h
vtkm::worklet::contourtree_augmented::NotNoSuchElementPredicate
Definition: NotNoSuchElementPredicate.h:67
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
vtkm::worklet::contourtree_distributed::FindRegularByGlobal
ExecutionObject to generate a device object to use FindRegularByGlobal for the HierarchicalContourTre...
Definition: FindRegularByGlobal.h:167
vtkm::cont::DataSet::GetField
const VTKM_CONT vtkm::cont::Field & GetField(vtkm::Id index) const
Retrieves a field by index.
Definition: DataSet.h:75
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::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::CollapseBranches
void CollapseBranches(const vtkm::cont::DataSet &hierarchicalTreeDataSet, vtkm::worklet::contourtree_augmented::IdArrayType &branchRoot)
routine to compute the local set of superarcs that root at a given one
Definition: HierarchicalVolumetricBranchDecomposer.h:443
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::UpVolume
vtkm::worklet::contourtree_augmented::IdArrayType UpVolume
working arrays - kept at class level to simplify debug print
Definition: HierarchicalVolumetricBranchDecomposer.h:164
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT
constexpr vtkm::Id NO_SUCH_ELEMENT
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:73
vtkm::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:54
vtkm::filter::scalar_topology::HierarchicalVolumetricBranchDecomposer::BestDownVolume
vtkm::worklet::contourtree_augmented::IdArrayType BestDownVolume
Definition: HierarchicalVolumetricBranchDecomposer.h:161
vtkm::worklet::contourtree_augmented::PrintEdgePairArray
void PrintEdgePairArray(std::string label, const EdgePairArray &edgePairArray, vtkm::Id nIndices, std::ostream &outStream=std::cout)
Definition: augmented/PrintVectors.h:325