VTK-m  2.0
MergeTree.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) 2016, Los Alamos National Security, LLC
11 // All rights reserved.
12 //
13 // Copyright 2016. Los Alamos National Security, LLC.
14 // This software was produced under U.S. Government contract DE-AC52-06NA25396
15 // for Los Alamos National Laboratory (LANL), which is operated by
16 // Los Alamos National Security, LLC for the U.S. Department of Energy.
17 // The U.S. Government has rights to use, reproduce, and distribute this
18 // software. NEITHER THE GOVERNMENT NOR LOS ALAMOS NATIONAL SECURITY, LLC
19 // MAKES ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LIABILITY FOR THE
20 // USE OF THIS SOFTWARE. If software is modified to produce derivative works,
21 // such modified software should be clearly marked, so as not to confuse it
22 // with the version available from LANL.
23 //
24 // Additionally, redistribution and use in source and binary forms, with or
25 // without modification, are permitted provided that the following conditions
26 // are met:
27 //
28 // 1. Redistributions of source code must retain the above copyright notice,
29 // this list of conditions and the following disclaimer.
30 // 2. Redistributions in binary form must reproduce the above copyright notice,
31 // this list of conditions and the following disclaimer in the documentation
32 // and/or other materials provided with the distribution.
33 // 3. Neither the name of Los Alamos National Security, LLC, Los Alamos
34 // National Laboratory, LANL, the U.S. Government, nor the names of its
35 // contributors may be used to endorse or promote products derived from
36 // this software without specific prior written permission.
37 //
38 // THIS SOFTWARE IS PROVIDED BY LOS ALAMOS NATIONAL SECURITY, LLC AND
39 // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
40 // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
41 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LOS ALAMOS
42 // NATIONAL SECURITY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
43 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
44 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
45 // USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
48 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 //============================================================================
50 
51 // This code is based on the algorithm presented in the paper:
52 // “Parallel Peak Pruning for Scalable SMP Contour Tree Computation.”
53 // Hamish Carr, Gunther Weber, Christopher Sewell, and James Ahrens.
54 // Proceedings of the IEEE Symposium on Large Data Analysis and Visualization
55 // (LDAV), October 2016, Baltimore, Maryland.
56 
57 //=======================================================================================
58 //
59 // COMMENTS:
60 //
61 // If we have computed the merge max & merge saddles correctly, we have substantially
62 // computed the merge tree already. However, it is not in the same format as we have
63 // previously represented it - in particular, we have yet to define all the merge arcs
64 // and the superarcs we have collected are not the same as before - i.e. they are already
65 // partially collapsed, but not according to the same rule as branch decomposition
66 // This unit is therefore to get the same result out as before so we can set up an
67 // automated crosscheck on the computation
68 //
69 // Compared to earlier versions, we have made a significant change - the merge tree
70 // is only computed on critical points, not on the full array. We therefore have a
71 // final step: to extend it to the full array. To do this, we will keep the initial
72 // mergeArcs array which records a maximum for each vertex, as we need the information
73 //
74 // Each maximum is now labelled with the saddle it is mapped to, or to the global min
75 // We therefore transfer this information back to the mergeArcs array, so that maxima
76 // (including saddles) are marked with the (lower) vertex that is the low end of their
77 // arc
78 
79 // BIG CHANGE: we can actually reuse the mergeArcs array for the final merge arc, for the
80 // chain maximum for each (regular) point, and for the merge saddle for maxima. This is
81 // slightly tricky and has some extra memory traffic, but it avoids duplicating arrays
82 // unnecessarily
83 //
84 // Initially, mergeArcs will be set to an outbound neighbour (or self for extrema), as the
85 // chainMaximum array used to be.
86 //
87 // After chains are built, then it will hold *AN* accessible extremum for each vertex.
88 //
89 // During the main processing, when an extremum is assigned a saddle, it will be stored
90 // here. Regular points will still store pointers to an extremum.
91 //
92 // After this is done, if the mergeArc points lower/higher, it is pointing to a saddle.
93 // Otherwise it is pointing to an extremum.
94 //
95 // And after the final pass, it will always point to the next along superarcs.
96 //
97 //=======================================================================================
98 
99 #ifndef vtkm_worklet_contourtree_mergetree_h
100 #define vtkm_worklet_contourtree_mergetree_h
101 
102 #include <vtkm/cont/Algorithm.h>
103 #include <vtkm/cont/ArrayCopy.h>
104 #include <vtkm/cont/ArrayHandle.h>
106 #include <vtkm/cont/DataSet.h>
107 
113 
114 //#define DEBUG_PRINT 1
115 //#define DEBUG_FUNCTION_ENTRY 1
116 //#define DEBUG_TIMING 1
117 
118 namespace vtkm
119 {
120 namespace worklet
121 {
122 namespace contourtree
123 {
124 
125 template <typename T, typename StorageType>
127 {
128 public:
129  // original data array
131 
132  // size of mesh
134 
135  // whether it is join or split tree
137 
138  // vector of arcs representing the merge tree
140 
141  // vector storing an extremum for each vertex
143 
144  // vector storing a saddle for each vertex
146 
147  // merge tree constructor
149  vtkm::Id NRows,
150  vtkm::Id NCols,
151  vtkm::Id NSlices,
152  bool IsJoinTree);
153 
154  // routine that does pointer-doubling in the mergeArc array
155  void BuildRegularChains();
156 
157  // routine that computes the augmented merge tree superarcs from the merge graph
159 
160  // routine that computes the augmented merge arcs from the superarcs
161  // this is separate from the previous routine because it also gets called separately
162  // once saddle & extrema are set for a given set of vertices, the merge arcs can be
163  // computed for any subset of those vertices that contains all of the critical points
165 
166  // debug routine
167  void DebugPrint(const char* message);
168 };
169 
170 // creates merge tree
171 template <typename T, typename StorageType>
173  vtkm::Id NRows,
174  vtkm::Id NCols,
175  vtkm::Id NSlices,
176  bool IsJoinTree)
177  : values(Values)
178  , nRows(NRows)
179  , nCols(NCols)
180  , nSlices(NSlices)
181  , isJoinTree(IsJoinTree)
182 {
184  nLogSteps = 1;
185  for (vtkm::Id shifter = NumVertices; shifter != 0; shifter >>= 1)
186  nLogSteps++;
187 
189 
193 
194  vtkm::cont::ArrayCopy(nullArray, mergeArcs);
195  vtkm::cont::ArrayCopy(nullArray, extrema);
196  vtkm::cont::ArrayCopy(nullArray, saddles);
197 }
198 
199 // routine that does pointer-doubling in the saddles array
200 template <typename T, typename StorageType>
202 {
203 #ifdef DEBUG_FUNCTION_ENTRY
204  std::cout << std::endl;
205  std::cout << "====================" << std::endl;
206  std::cout << "Build Regular Chains" << std::endl;
207  std::cout << "====================" << std::endl;
208  std::cout << std::endl;
209 #endif
210  // 2. Create a temporary array so that we can alternate writing between them
211  vtkm::cont::ArrayHandle<vtkm::Id> temporaryArcs;
212  temporaryArcs.Allocate(NumVertices);
213 
214  vtkm::cont::ArrayHandleIndex vertexIndexArray(NumVertices);
215  ChainDoubler chainDoubler;
216  vtkm::worklet::DispatcherMapField<ChainDoubler> chainDoublerDispatcher(chainDoubler);
217 
218  // 3. Apply pointer-doubling to build chains to maxima, rocking between two arrays
219  for (vtkm::Id logStep = 0; logStep < nLogSteps; logStep++)
220  {
221  chainDoublerDispatcher.Invoke(vertexIndexArray, // input
222  extrema); // i/o whole array
223  }
224 } // BuildRegularChains()
225 
226 // routine that computes the augmented merge tree from the merge graph
227 template <typename T, typename StorageType>
229 {
230 #ifdef DEBUG_FUNCTION_ENTRY
231  std::cout << std::endl;
232  std::cout << "=================================" << std::endl;
233  std::cout << "Compute Augmented Merge Superarcs" << std::endl;
234  std::cout << "=================================" << std::endl;
235  std::cout << std::endl;
236 #endif
237 
238  // our first step is to assign every vertex to a pseudo-extremum based on how the
239  // vertex ascends to a extremum, and the sequence of pruning for the extremum
240  // to do this, we iterate as many times as pruning occurred
241 
242  // we run a little loop for each element until it finds its join superarc
243  // expressed as a functor.
244  vtkm::Id nExtrema = extrema.GetNumberOfValues();
245 
246  JoinSuperArcFinder<T> joinSuperArcFinder(isJoinTree);
247  vtkm::worklet::DispatcherMapField<JoinSuperArcFinder<T>> joinSuperArcFinderDispatcher(
248  joinSuperArcFinder);
249  vtkm::cont::ArrayHandleIndex vertexIndexArray(nExtrema);
250 
251  joinSuperArcFinderDispatcher.Invoke(vertexIndexArray, // input
252  values, // input (whole array)
253  saddles, // i/o (whole array)
254  extrema); // i/o (whole array)
255 
256 // at the end of this, all vertices should have a pseudo-extremum in the extrema array
257 // and a pseudo-saddle in the saddles array
258 #ifdef DEBUG_PRINT
259  DebugPrint("Merge Superarcs Set");
260 #endif
261 } // ComputeAugmentedSuperarcs()
262 
263 // routine that computes the augmented merge arcs from the superarcs
264 // this is separate from the previous routine because it also gets called separately
265 // once saddle & extrema are set for a given set of vertices, the merge arcs can be
266 // computed for any subset of those vertices that contains all of the critical points
267 template <typename T, typename StorageType>
269 {
270 #ifdef DEBUG_FUNCTION_ENTRY
271  std::cout << std::endl;
272  std::cout << "============================" << std::endl;
273  std::cout << "Compute Augmented Merge Arcs" << std::endl;
274  std::cout << "============================" << std::endl;
275  std::cout << std::endl;
276 #endif
277 
278  // create a vector of indices for sorting
279  vtkm::Id nCriticalVerts = vertices.GetNumberOfValues();
281  vtkm::cont::ArrayCopy(vertices, vertexSorter);
282 
283  // We sort by pseudo-maximum to establish the extents
284  vtkm::cont::Algorithm::Sort(vertexSorter,
285  VertexMergeComparator<T, StorageType>(values, extrema, isJoinTree));
286 #ifdef DEBUG_PRINT
287  DebugPrint("Sorting Complete");
288 #endif
289 
291  vtkm::cont::ArrayCopy(noVertArray, mergeArcs);
292 
293  vtkm::cont::ArrayHandleIndex critVertexIndexArray(nCriticalVerts);
294  JoinArcConnector joinArcConnector;
295  vtkm::worklet::DispatcherMapField<JoinArcConnector> joinArcConnectorDispatcher(joinArcConnector);
296 
297  joinArcConnectorDispatcher.Invoke(critVertexIndexArray, // input
298  vertexSorter, // input (whole array)
299  extrema, // input (whole array)
300  saddles, // input (whole array)
301  mergeArcs); // output (whole array)
302 #ifdef DEBUG_PRINT
303  DebugPrint("Augmented Arcs Set");
304 #endif
305 } // ComputeAugmentedArcs()
306 
307 // debug routine
308 template <typename T, typename StorageType>
309 void MergeTree<T, StorageType>::DebugPrint(const char* message)
310 {
311  std::cout << "---------------------------" << std::endl;
312  std::cout << std::string(message) << std::endl;
313  std::cout << "---------------------------" << std::endl;
314  std::cout << std::endl;
315 
316  PrintLabelledBlock("Values", values, nRows * nSlices, nCols);
317  std::cout << std::endl;
318  PrintLabelledBlock("MergeArcs", mergeArcs, nRows, nCols);
319  std::cout << std::endl;
320  PrintLabelledBlock("Extrema", extrema, nRows, nCols);
321  std::cout << std::endl;
322  PrintLabelledBlock("Saddles", saddles, nRows, nCols);
323  std::cout << std::endl;
324 } // DebugPrint()
325 }
326 }
327 }
328 #endif
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< T, StorageType >
ArrayHandle.h
JoinSuperArcFinder.h
vtkm::worklet::contourtree::MergeTree::MergeTree
MergeTree(const vtkm::cont::ArrayHandle< T, StorageType > &Values, vtkm::Id NRows, vtkm::Id NCols, vtkm::Id NSlices, bool IsJoinTree)
Definition: MergeTree.h:172
vtkm::worklet::contourtree::VertexMergeComparator
Definition: VertexMergeComparator.h:92
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
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::worklet::contourtree::MergeTree
Definition: MergeTree.h:126
vtkm::worklet::contourtree::MergeTree::nRows
vtkm::Id nRows
Definition: MergeTree.h:133
vtkm::cont::Algorithm::Sort
static VTKM_CONT void Sort(vtkm::cont::DeviceAdapterId devId, vtkm::cont::ArrayHandle< T, Storage > &values)
Definition: Algorithm.h:965
ArrayHandleConstant.h
vtkm::worklet::contourtree::MergeTree::ComputeAugmentedArcs
void ComputeAugmentedArcs(vtkm::cont::ArrayHandle< vtkm::Id > &vertices)
Definition: MergeTree.h:268
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
ArrayCopy.h
vtkm::worklet::contourtree::MergeTree::extrema
vtkm::cont::ArrayHandle< vtkm::Id > extrema
Definition: MergeTree.h:142
vtkm::worklet::contourtree::MergeTree::saddles
vtkm::cont::ArrayHandle< vtkm::Id > saddles
Definition: MergeTree.h:145
vtkm::worklet::contourtree::MergeTree::isJoinTree
bool isJoinTree
Definition: MergeTree.h:136
vtkm::worklet::DispatcherMapField
Dispatcher for worklets that inherit from WorkletMapField.
Definition: DispatcherMapField.h:25
Algorithm.h
vtkm::worklet::contourtree::MergeTree::nSlices
vtkm::Id nSlices
Definition: MergeTree.h:133
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::contourtree::MergeTree::nCols
vtkm::Id nCols
Definition: MergeTree.h:133
NO_VERTEX_ASSIGNED
#define NO_VERTEX_ASSIGNED
Definition: filter/scalar_topology/worklet/contourtree/Types.h:77
ChainDoubler.h
vtkm::cont::ArrayHandleConstant
An array handle with a constant value.
Definition: ArrayHandleConstant.h:63
vtkm::worklet::contourtree::MergeTree::NumVertices
vtkm::Id NumVertices
Definition: MergeTree.h:133
vtkm::worklet::contourtree::PrintLabelledBlock
void PrintLabelledBlock(std::string label, const vtkm::cont::ArrayHandle< T, StorageType > &dVec, vtkm::Id nRows, vtkm::Id nColumns)
Definition: PrintVectors.h:232
vtkm::worklet::contourtree::MergeTree::mergeArcs
vtkm::cont::ArrayHandle< vtkm::Id > mergeArcs
Definition: MergeTree.h:139
VertexMergeComparator.h
vtkm::worklet::contourtree::ChainDoubler
Definition: ChainDoubler.h:91
vtkm::worklet::contourtree::JoinSuperArcFinder
Definition: JoinSuperArcFinder.h:99
PrintVectors.h
vtkm::worklet::contourtree::MergeTree::BuildRegularChains
void BuildRegularChains()
Definition: MergeTree.h:201
vtkm::worklet::contourtree::MergeTree::ComputeAugmentedSuperarcs
void ComputeAugmentedSuperarcs()
Definition: MergeTree.h:228
vtkm::worklet::contourtree::MergeTree::nLogSteps
vtkm::Id nLogSteps
Definition: MergeTree.h:133
vtkm::worklet::contourtree::JoinArcConnector
Definition: JoinArcConnector.h:86
vtkm::worklet::contourtree::MergeTree::values
const vtkm::cont::ArrayHandle< T, StorageType > & values
Definition: MergeTree.h:130
DataSet.h
JoinArcConnector.h
vtkm::cont::ArrayHandleIndex
An implicit array handle containing the its own indices.
Definition: ArrayHandleIndex.h:54
vtkm::worklet::contourtree::MergeTree::DebugPrint
void DebugPrint(const char *message)
Definition: MergeTree.h:309