VTK-m  2.0
Branch.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 // This code is an extension of the algorithm presented in the paper:
43 // Parallel Peak Pruning for Scalable SMP Contour Tree Computation.
44 // Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
45 // Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
46 // (LDAV), October 2016, Baltimore, Maryland.
47 //
48 // The PPP2 algorithm and software were jointly developed by
49 // Hamish Carr (University of Leeds), Gunther H. Weber (LBNL), and
50 // Oliver Ruebel (LBNL)
51 //==============================================================================
52 
53 #ifndef vtk_m_worklet_contourtree_augmented_process_contourtree_inc_branch_h
54 #define vtk_m_worklet_contourtree_augmented_process_contourtree_inc_branch_h
55 
56 #include <vtkm/cont/ArrayHandle.h>
60 
61 #include <cmath>
62 
63 namespace vtkm
64 {
65 namespace worklet
66 {
67 namespace contourtree_augmented
68 {
69 namespace process_contourtree_inc
70 {
71 
72 // TODO The pointered list structure and use of std::vector don't seem to fit well with using Branch with VTKM
73 template <typename T>
74 class Branch
75 {
76 public:
77  vtkm::Id OriginalId; // Index of the extremum in the mesh
78  vtkm::Id Extremum; // Index of the extremum in the mesh
79  T ExtremumVal; // Value at the extremum:w
80  vtkm::Id Saddle; // Index of the saddle in the mesh (or minimum for root branch)
81  T SaddleVal; // Corresponding value
82  vtkm::Id Volume; // Volume
83  Branch<T>* Parent; // Pointer to parent, or nullptr if no parent
84  std::vector<Branch<T>*> Children; // List of pointers to children
85 
86  // Create branch decomposition from contour tree
87  template <typename StorageType>
89  const IdArrayType& contourTreeSuperparents,
90  const IdArrayType& contourTreeSupernodes,
91  const IdArrayType& whichBranch,
92  const IdArrayType& branchMinimum,
93  const IdArrayType& branchMaximum,
94  const IdArrayType& branchSaddle,
95  const IdArrayType& branchParent,
96  const IdArrayType& sortOrder,
98  bool dataFieldIsSorted);
99 
100  // Simplify branch composition down to target size (i.e., consisting of targetSize branches)
101  void SimplifyToSize(vtkm::Id targetSize, bool usePersistenceSorter = true);
102 
103  // Print the branch decomposition
104  void PrintBranchDecomposition(std::ostream& os, std::string::size_type indent = 0) const;
105 
106  // Persistence of branch
107  T Persistence() { return std::fabs(ExtremumVal - SaddleVal); }
108 
109  // Destroy branch (deleting children and propagating Volume to parent)
110  ~Branch();
111 
112  // Compute list of relevant/interesting isovalues
113  void GetRelevantValues(int type, T eps, std::vector<T>& values) const;
114 
115  void AccumulateIntervals(int type, T eps, PiecewiseLinearFunction<T>& plf) const;
116 
117 private:
118  // Private default constructore to ensure that branch decomposition can only be created from a contour tree or loaded from storate (via static methods)
120  : Extremum((vtkm::Id)vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT)
121  , ExtremumVal(0)
122  , Saddle((vtkm::Id)vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT)
123  , SaddleVal(0)
124  , Volume(0)
125  , Parent(nullptr)
126  , Children()
127  {
128  }
129 
130  // Remove symbolic perturbation, i.e., branches with zero persistence
132 }; // class Branch
133 
134 
135 template <typename T>
137 { // PersistenceSorter()
138  inline bool operator()(Branch<T>* a, Branch<T>* b) { return a->Persistence() < b->Persistence(); }
139 }; // PersistenceSorter()
140 
141 
142 template <typename T>
144 { // VolumeSorter()
145  inline bool operator()(Branch<T>* a, Branch<T>* b) { return a->Volume < b->Volume; }
146 }; // VolumeSorter()
147 
148 
149 template <typename T>
150 template <typename StorageType>
152  const IdArrayType& contourTreeSuperparents,
153  const IdArrayType& contourTreeSupernodes,
154  const IdArrayType& whichBranch,
155  const IdArrayType& branchMinimum,
156  const IdArrayType& branchMaximum,
157  const IdArrayType& branchSaddle,
158  const IdArrayType& branchParent,
159  const IdArrayType& sortOrder,
161  bool dataFieldIsSorted)
162 { // C)omputeBranchDecomposition()
163  auto branchMinimumPortal = branchMinimum.ReadPortal();
164  auto branchMaximumPortal = branchMaximum.ReadPortal();
165  auto branchSaddlePortal = branchSaddle.ReadPortal();
166  auto branchParentPortal = branchParent.ReadPortal();
167  auto sortOrderPortal = sortOrder.ReadPortal();
168  auto supernodesPortal = contourTreeSupernodes.ReadPortal();
169  auto dataFieldPortal = dataField.ReadPortal();
170  vtkm::Id nBranches = branchSaddle.GetNumberOfValues();
171  std::vector<Branch<T>*> branches;
172  Branch<T>* root = nullptr;
173  branches.reserve(static_cast<std::size_t>(nBranches));
174 
175  for (int branchID = 0; branchID < nBranches; ++branchID)
176  branches.push_back(new Branch<T>);
177 
178  // Reconstruct explicit branch decomposition from array representation
179  for (std::size_t branchID = 0; branchID < static_cast<std::size_t>(nBranches); ++branchID)
180  {
181  branches[branchID]->OriginalId = static_cast<vtkm::Id>(branchID);
182  if (!NoSuchElement(branchSaddlePortal.Get(static_cast<vtkm::Id>(branchID))))
183  {
184  branches[branchID]->Saddle = MaskedIndex(
185  supernodesPortal.Get(MaskedIndex(branchSaddlePortal.Get(static_cast<vtkm::Id>(branchID)))));
186  vtkm::Id branchMin = MaskedIndex(supernodesPortal.Get(
187  MaskedIndex(branchMinimumPortal.Get(static_cast<vtkm::Id>(branchID)))));
188  vtkm::Id branchMax = MaskedIndex(supernodesPortal.Get(
189  MaskedIndex(branchMaximumPortal.Get(static_cast<vtkm::Id>(branchID)))));
190  if (branchMin < branches[branchID]->Saddle)
191  branches[branchID]->Extremum = branchMin;
192  else if (branchMax > branches[branchID]->Saddle)
193  branches[branchID]->Extremum = branchMax;
194  else
195  {
196  std::cerr << "Internal error";
197  return 0;
198  }
199  }
200  else
201  {
202  branches[branchID]->Saddle =
203  supernodesPortal.Get(MaskedIndex(branchMinimumPortal.Get(static_cast<vtkm::Id>(branchID))));
204  branches[branchID]->Extremum =
205  supernodesPortal.Get(MaskedIndex(branchMaximumPortal.Get(static_cast<vtkm::Id>(branchID))));
206  }
207 
208  if (dataFieldIsSorted)
209  {
210  branches[branchID]->SaddleVal = dataFieldPortal.Get(branches[branchID]->Saddle);
211  branches[branchID]->ExtremumVal = dataFieldPortal.Get(branches[branchID]->Extremum);
212  }
213  else
214  {
215  branches[branchID]->SaddleVal =
216  dataFieldPortal.Get(sortOrderPortal.Get(branches[branchID]->Saddle));
217  branches[branchID]->ExtremumVal =
218  dataFieldPortal.Get(sortOrderPortal.Get(branches[branchID]->Extremum));
219  }
220 
221  branches[branchID]->Saddle = sortOrderPortal.Get(branches[branchID]->Saddle);
222  branches[branchID]->Extremum = sortOrderPortal.Get(branches[branchID]->Extremum);
223 
224  if (NoSuchElement(branchParentPortal.Get(static_cast<vtkm::Id>(branchID))))
225  {
226  root = branches[branchID]; // No parent -> this is the root branch
227  }
228  else
229  {
230  branches[branchID]->Parent = branches[static_cast<size_t>(
231  MaskedIndex(branchParentPortal.Get(static_cast<vtkm::Id>(branchID))))];
232  branches[branchID]->Parent->Children.push_back(branches[branchID]);
233  }
234  }
235 
236  // FIXME: This is a somewhat hackish way to compute the Volume, but it works
237  // It would probably be better to compute this from the already computed Volume information
238  auto whichBranchPortal = whichBranch.ReadPortal();
239  auto superparentsPortal = contourTreeSuperparents.ReadPortal();
240  for (vtkm::Id i = 0; i < contourTreeSuperparents.GetNumberOfValues(); i++)
241  {
242  branches[static_cast<size_t>(
243  MaskedIndex(whichBranchPortal.Get(MaskedIndex(superparentsPortal.Get(i)))))]
244  ->Volume++; // Increment Volume
245  }
246  if (root)
247  {
249  }
250 
251  return root;
252 } // ComputeBranchDecomposition()
253 
254 
255 template <typename T>
256 void Branch<T>::SimplifyToSize(vtkm::Id targetSize, bool usePersistenceSorter)
257 { // SimplifyToSize()
258  if (targetSize <= 1)
259  return;
260 
261  // Top-down simplification, starting from one branch and adding in the rest on a biggest-first basis
262  std::vector<Branch<T>*> q;
263  q.push_back(this);
264 
265  std::vector<Branch<T>*> active;
266  while (active.size() < static_cast<std::size_t>(targetSize) && !q.empty())
267  {
268  if (usePersistenceSorter)
269  {
270  std::pop_heap(
271  q.begin(),
272  q.end(),
274  T>()); // FIXME: This should be Volume, but we were doing this wrong for the demo, so let's start with doing this wrong here, too
275  }
276  else
277  {
278  std::pop_heap(
279  q.begin(),
280  q.end(),
281  VolumeSorter<
282  T>()); // FIXME: This should be Volume, but we were doing this wrong for the demo, so let's start with doing this wrong here, too
283  }
284  Branch<T>* b = q.back();
285  q.pop_back();
286 
287  active.push_back(b);
288 
289  for (Branch<T>* c : b->Children)
290  {
291  q.push_back(c);
292  if (usePersistenceSorter)
293  {
294  std::push_heap(q.begin(), q.end(), PersistenceSorter<T>());
295  }
296  else
297  {
298  std::push_heap(q.begin(), q.end(), VolumeSorter<T>());
299  }
300  }
301  }
302 
303  // Rest are inactive
304  for (Branch<T>* b : q)
305  {
306  // Hackish, remove c from its parents child list
307  if (b->Parent)
308  b->Parent->Children.erase(
309  std::remove(b->Parent->Children.begin(), b->Parent->Children.end(), b));
310 
311  delete b;
312  }
313 } // SimplifyToSize()
314 
315 
316 template <typename T>
317 void Branch<T>::PrintBranchDecomposition(std::ostream& os, std::string::size_type indent) const
318 { // PrintBranchDecomposition()
319  os << std::string(indent, ' ') << "{" << std::endl;
320  os << std::string(indent, ' ') << " Saddle = " << SaddleVal << " (" << Saddle << ")"
321  << std::endl;
322  os << std::string(indent, ' ') << " Extremum = " << ExtremumVal << " (" << Extremum << ")"
323  << std::endl;
324  os << std::string(indent, ' ') << " Volume = " << Volume << std::endl;
325  if (!Children.empty())
326  {
327  os << std::string(indent, ' ') << " Children = [" << std::endl;
328  for (Branch<T>* c : Children)
329  c->PrintBranchDecomposition(os, indent + 4);
330  os << std::string(indent, ' ') << std::string(indent, ' ') << " ]" << std::endl;
331  }
332  os << std::string(indent, ' ') << "}" << std::endl;
333 } // PrintBranchDecomposition()
334 
335 
336 template <typename T>
338 { // ~Branch()
339  for (Branch<T>* c : Children)
340  delete c;
341  if (Parent)
342  Parent->Volume += Volume;
343 } // ~Branch()
344 
345 
346 // TODO this recursive accumlation of values does not lend itself well to the use of VTKM data structures
347 template <typename T>
348 void Branch<T>::GetRelevantValues(int type, T eps, std::vector<T>& values) const
349 { // GetRelevantValues()
350  T val;
351 
352  bool isMax = false;
353  if (ExtremumVal > SaddleVal)
354  isMax = true;
355 
356  switch (type)
357  {
358  default:
359  case 0:
360  val = SaddleVal + (isMax ? +eps : -eps);
361  break;
362  case 1:
363  val = T(0.5f) * (ExtremumVal + SaddleVal);
364  break;
365  case 2:
366  val = ExtremumVal + (isMax ? -eps : +eps);
367  break;
368  }
369  if (Parent)
370  values.push_back({ val });
371  for (Branch* c : Children)
372  c->GetRelevantValues(type, eps, values);
373 } // GetRelevantValues()
374 
375 
376 template <typename T>
378 { //AccumulateIntervals()
379  bool isMax = (ExtremumVal > SaddleVal);
380  T val;
381 
382  switch (type)
383  {
384  default:
385  case 0:
386  val = SaddleVal + (isMax ? +eps : -eps);
387  break;
388  case 1:
389  val = T(0.5f) * (ExtremumVal + SaddleVal);
390  break;
391  case 2:
392  val = ExtremumVal + (isMax ? -eps : +eps);
393  break;
394  }
395 
396  if (Parent)
397  {
399  addPLF.addSample(SaddleVal, 0.0);
400  addPLF.addSample(ExtremumVal, 0.0);
401  addPLF.addSample(val, 1.0);
402  plf += addPLF;
403  }
404  for (Branch<T>* c : Children)
405  c->AccumulateIntervals(type, eps, plf);
406 } // AccumulateIntervals()
407 
408 
409 template <typename T>
411 { // removeSymbolicPerturbation()
412  std::vector<Branch<T>*> newChildren; // Temporary list of children that are not flat
413 
414  for (Branch<T>* c : Children)
415  {
416  // First recursively remove symbolic perturbation (zero persistence branches) for all children below the current child
417  // Necessary to be able to detect whether we can remove the current child
418  c->removeSymbolicPerturbation();
419 
420  // Does child have zero persistence (flat region)
421  if (c->ExtremumVal == c->SaddleVal && c->Children.empty())
422  {
423  // If yes, then we get its associated Volume and delete it
424  delete c; // Will add Volume to parent, i.e., us
425  }
426  else
427  {
428  // Otherwise, keep child
429  newChildren.push_back(c);
430  }
431  }
432  // Swap out new list of children
433  Children.swap(newChildren);
434 } // removeSymbolicPerturbation()
435 
436 } // process_contourtree_inc
437 } // namespace contourtree_augmented
438 } // namespace worklet
439 } // namespace vtkm
440 
441 #endif // vtk_m_worklet_contourtree_augmented_process_contourtree_inc_branch_h
vtkm::cont::ArrayHandle::GetNumberOfValues
VTKM_CONT vtkm::Id GetNumberOfValues() const
Returns the number of entries in the array.
Definition: ArrayHandle.h:448
vtkm::cont::ArrayHandle< vtkm::Id >
ArrayHandle.h
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PersistenceSorter
Definition: Branch.h:136
PiecewiseLinearFunction.h
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::OriginalId
vtkm::Id OriginalId
Definition: Branch.h:77
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::GetRelevantValues
void GetRelevantValues(int type, T eps, std::vector< T > &values) const
Definition: Branch.h:348
vtkm::worklet::contourtree_augmented::process_contourtree_inc::VolumeSorter
Definition: Branch.h:143
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PersistenceSorter::operator()
bool operator()(Branch< T > *a, Branch< T > *b)
Definition: Branch.h:138
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::PrintBranchDecomposition
void PrintBranchDecomposition(std::ostream &os, std::string::size_type indent=0) const
Definition: Branch.h:317
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Saddle
vtkm::Id Saddle
Definition: Branch.h:80
vtkm::worklet::contourtree_augmented::MaskedIndex
VTKM_EXEC_CONT vtkm::Id MaskedIndex(vtkm::Id flaggedIndex)
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:127
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::SaddleVal
T SaddleVal
Definition: Branch.h:81
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PiecewiseLinearFunction
Definition: PiecewiseLinearFunction.h:82
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Persistence
T Persistence()
Definition: Branch.h:107
vtkm::worklet::contourtree_augmented::NoSuchElement
VTKM_EXEC_CONT bool NoSuchElement(vtkm::Id flaggedIndex)
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:97
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::ComputeBranchDecomposition
static Branch< T > * ComputeBranchDecomposition(const IdArrayType &contourTreeSuperparents, const IdArrayType &contourTreeSupernodes, const IdArrayType &whichBranch, const IdArrayType &branchMinimum, const IdArrayType &branchMaximum, const IdArrayType &branchSaddle, const IdArrayType &branchParent, const IdArrayType &sortOrder, const vtkm::cont::ArrayHandle< T, StorageType > &dataField, bool dataFieldIsSorted)
Definition: Branch.h:151
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::ExtremumVal
T ExtremumVal
Definition: Branch.h:79
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Volume
vtkm::Id Volume
Definition: Branch.h:82
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Extremum
vtkm::Id Extremum
Definition: Branch.h:78
Types.h
vtkm::worklet::contourtree_augmented::process_contourtree_inc::PiecewiseLinearFunction::addSample
void addSample(T sx, T sy)
Definition: PiecewiseLinearFunction.h:87
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::~Branch
~Branch()
Definition: Branch.h:337
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Parent
Branch< T > * Parent
Definition: Branch.h:83
vtkm::worklet::contourtree_augmented::process_contourtree_inc::VolumeSorter::operator()
bool operator()(Branch< T > *a, Branch< T > *b)
Definition: Branch.h:145
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::SimplifyToSize
void SimplifyToSize(vtkm::Id targetSize, bool usePersistenceSorter=true)
Definition: Branch.h:256
vtkm::cont::ArrayHandle::ReadPortal
VTKM_CONT ReadPortalType ReadPortal() const
Get an array portal that can be used in the control environment.
Definition: ArrayHandle.h:414
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Children
std::vector< Branch< T > * > Children
Definition: Branch.h:84
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::Branch
Branch()
Definition: Branch.h:119
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch
Definition: Branch.h:74
ContourTree.h
vtkm::worklet::contourtree_augmented::NO_SUCH_ELEMENT
constexpr vtkm::Id NO_SUCH_ELEMENT
Definition: filter/scalar_topology/worklet/contourtree_augmented/Types.h:73
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::AccumulateIntervals
void AccumulateIntervals(int type, T eps, PiecewiseLinearFunction< T > &plf) const
Definition: Branch.h:377
vtkm::worklet::contourtree_augmented::process_contourtree_inc::Branch::removeSymbolicPerturbation
void removeSymbolicPerturbation()
Definition: Branch.h:410