VTK-m  2.0
ReverseConnectivityBuilder.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 #ifndef vtk_m_cont_internal_ReverseConnectivityBuilder_h
11 #define vtk_m_cont_internal_ReverseConnectivityBuilder_h
12 
13 #include <vtkm/cont/Algorithm.h>
14 #include <vtkm/cont/ArrayHandle.h>
18 
19 #include <vtkm/cont/AtomicArray.h>
20 #include <vtkm/exec/FunctorBase.h>
21 
22 #include <utility>
23 
24 namespace vtkm
25 {
26 namespace cont
27 {
28 namespace internal
29 {
30 
31 namespace rcb
32 {
33 
34 template <typename AtomicHistogram, typename ConnInPortal, typename RConnToConnIdxCalc>
35 struct BuildHistogram : public vtkm::exec::FunctorBase
36 {
37  AtomicHistogram Histo;
38  ConnInPortal Conn;
39  RConnToConnIdxCalc IdxCalc;
40 
41  VTKM_CONT
42  BuildHistogram(const AtomicHistogram& histo,
43  const ConnInPortal& conn,
44  const RConnToConnIdxCalc& idxCalc)
45  : Histo(histo)
46  , Conn(conn)
47  , IdxCalc(idxCalc)
48  {
49  }
50 
51  VTKM_EXEC
52  void operator()(vtkm::Id rconnIdx) const
53  {
54  // Compute the connectivity array index (skipping cell length entries)
55  const vtkm::Id connIdx = this->IdxCalc(rconnIdx);
56  const vtkm::Id ptId = this->Conn.Get(connIdx);
57  this->Histo.Add(ptId, 1);
58  }
59 };
60 
61 template <typename AtomicHistogram,
62  typename ConnInPortal,
63  typename ROffsetInPortal,
64  typename RConnOutPortal,
65  typename RConnToConnIdxCalc,
66  typename ConnIdxToCellIdxCalc>
67 struct GenerateRConn : public vtkm::exec::FunctorBase
68 {
69  AtomicHistogram Histo;
70  ConnInPortal Conn;
71  ROffsetInPortal ROffsets;
72  RConnOutPortal RConn;
73  RConnToConnIdxCalc IdxCalc;
74  ConnIdxToCellIdxCalc CellIdCalc;
75 
76  VTKM_CONT
77  GenerateRConn(const AtomicHistogram& histo,
78  const ConnInPortal& conn,
79  const ROffsetInPortal& rOffsets,
80  const RConnOutPortal& rconn,
81  const RConnToConnIdxCalc& idxCalc,
82  const ConnIdxToCellIdxCalc& cellIdCalc)
83  : Histo(histo)
84  , Conn(conn)
85  , ROffsets(rOffsets)
86  , RConn(rconn)
87  , IdxCalc(idxCalc)
88  , CellIdCalc(cellIdCalc)
89  {
90  }
91 
92  VTKM_EXEC
93  void operator()(vtkm::Id inputIdx) const
94  {
95  // Compute the connectivity array index (skipping cell length entries)
96  const vtkm::Id connIdx = this->IdxCalc(inputIdx);
97  const vtkm::Id ptId = this->Conn.Get(connIdx);
98 
99  // Compute the cell id:
100  const vtkm::Id cellId = this->CellIdCalc(connIdx);
101 
102  // Find the base offset for this point id:
103  const vtkm::Id baseOffset = this->ROffsets.Get(ptId);
104 
105  // Find the next unused index for this point id
106  const vtkm::Id nextAvailable = this->Histo.Add(ptId, 1);
107 
108  // Update the final location in the RConn table with the cellId
109  const vtkm::Id rconnIdx = baseOffset + nextAvailable;
110  this->RConn.Set(rconnIdx, cellId);
111  }
112 };
113 }
129 class ReverseConnectivityBuilder
130 {
131 public:
132  VTKM_CONT
133  template <typename ConnArray,
134  typename RConnArray,
135  typename ROffsetsArray,
136  typename RConnToConnIdxCalc,
137  typename ConnIdxToCellIdxCalc>
138  inline void Run(const ConnArray& conn,
139  RConnArray& rConn,
140  ROffsetsArray& rOffsets,
141  const RConnToConnIdxCalc& rConnToConnCalc,
142  const ConnIdxToCellIdxCalc& cellIdCalc,
143  vtkm::Id numberOfPoints,
144  vtkm::Id rConnSize,
146  {
147  vtkm::cont::Token connToken;
148  auto connPortal = conn.PrepareForInput(device, connToken);
149  auto zeros = vtkm::cont::make_ArrayHandleConstant(vtkm::IdComponent{ 0 }, numberOfPoints);
150 
151  // Compute RConn offsets by atomically building a histogram and doing an
152  // extended scan.
153  //
154  // Example:
155  // (in) Conn: | 3 0 1 2 | 3 0 1 3 | 3 0 3 4 | 3 3 4 5 |
156  // (out) RNumIndices: 3 2 1 3 2 1
157  // (out) RIdxOffsets: 0 3 5 6 9 11 12
159  { // allocate and zero the numIndices array:
160  vtkm::cont::Algorithm::Copy(device, zeros, rNumIndices);
161  }
162 
163  { // Build histogram:
164  vtkm::cont::AtomicArray<vtkm::IdComponent> atomicCounter{ rNumIndices };
165  vtkm::cont::Token token;
166  auto ac = atomicCounter.PrepareForExecution(device, token);
167  using BuildHisto =
168  rcb::BuildHistogram<decltype(ac), decltype(connPortal), RConnToConnIdxCalc>;
169  BuildHisto histoGen{ ac, connPortal, rConnToConnCalc };
170 
171  vtkm::cont::Algorithm::Schedule(device, histoGen, rConnSize);
172  }
173 
174  { // Compute offsets:
176  device, vtkm::cont::make_ArrayHandleCast<vtkm::Id>(rNumIndices), rOffsets);
177  }
178 
179  { // Reset the numIndices array to 0's:
180  vtkm::cont::Algorithm::Copy(device, zeros, rNumIndices);
181  }
182 
183  // Fill the connectivity table:
184  // 1) Lookup each point idx base offset.
185  // 2) Use the atomic histogram to find the next available slot for this
186  // pt id in RConn.
187  // 3) Compute the cell id from the connectivity index
188  // 4) Update RConn[nextSlot] = cellId
189  //
190  // Example:
191  // (in) Conn: | 3 0 1 2 | 3 0 1 3 | 3 0 3 4 | 3 3 4 5 |
192  // (inout) RNumIndices: 0 0 0 0 0 0 (Initial)
193  // (inout) RNumIndices: 3 2 1 3 2 1 (Final)
194  // (in) RIdxOffsets: 0 3 5 6 9 11
195  // (out) RConn: | 0 1 2 | 0 1 | 0 | 1 2 3 | 2 3 | 3 |
196  {
197  vtkm::cont::AtomicArray<vtkm::IdComponent> atomicCounter{ rNumIndices };
198  vtkm::cont::Token token;
199  auto ac = atomicCounter.PrepareForExecution(device, token);
200  auto rOffsetPortal = rOffsets.PrepareForInput(device, token);
201  auto rConnPortal = rConn.PrepareForOutput(rConnSize, device, token);
202 
203  using GenRConnT = rcb::GenerateRConn<decltype(ac),
204  decltype(connPortal),
205  decltype(rOffsetPortal),
206  decltype(rConnPortal),
207  RConnToConnIdxCalc,
208  ConnIdxToCellIdxCalc>;
209  GenRConnT rConnGen{ ac, connPortal, rOffsetPortal, rConnPortal, rConnToConnCalc, cellIdCalc };
210 
211  vtkm::cont::Algorithm::Schedule(device, rConnGen, rConnSize);
212  }
213  }
214 };
215 
216 // Pass through (needed for ReverseConnectivityBuilder)
217 struct PassThrough
218 {
219  VTKM_EXEC vtkm::Id operator()(const vtkm::Id& val) const { return val; }
220 };
221 
222 // Compute cell id from input connectivity:
223 // Find the upper bound of the conn idx in the offsets table and subtract 1
224 //
225 // Example:
226 // Offsets: | 0 | 3 | 6 | 10 |
227 // Conn: | 0 1 2 | 0 1 3 | 2 4 5 6 | 1 3 5 |
228 // ConnIdx: | 0 1 2 | 3 4 5 | 6 7 8 9 | 10 11 12 |
229 // UpprBnd: | 1 1 1 | 2 2 2 | 3 3 3 3 | 4 4 4 |
230 // CellIdx: | 0 0 0 | 1 1 1 | 2 2 2 2 | 3 3 3 |
231 template <typename OffsetsPortalType>
232 struct ConnIdxToCellIdCalc
233 {
234  OffsetsPortalType Offsets;
235 
236  VTKM_CONT
237  ConnIdxToCellIdCalc(const OffsetsPortalType& offsets)
238  : Offsets(offsets)
239  {
240  }
241 
242  VTKM_EXEC
243  vtkm::Id operator()(vtkm::Id inIdx) const
244  {
245  // Compute the upper bound index:
246  vtkm::Id upperBoundIdx;
247  {
248  vtkm::Id first = 0;
249  vtkm::Id length = this->Offsets.GetNumberOfValues();
250 
251  while (length > 0)
252  {
253  vtkm::Id halfway = length / 2;
254  vtkm::Id pos = first + halfway;
255  vtkm::Id val = this->Offsets.Get(pos);
256  if (val <= inIdx)
257  {
258  first = pos + 1;
259  length -= halfway + 1;
260  }
261  else
262  {
263  length = halfway;
264  }
265  }
266 
267  upperBoundIdx = first;
268  }
269 
270  return upperBoundIdx - 1;
271  }
272 };
273 
274 // Much easier for CellSetSingleType:
275 struct ConnIdxToCellIdCalcSingleType
276 {
277  vtkm::IdComponent CellSize;
278 
279  VTKM_CONT
280  ConnIdxToCellIdCalcSingleType(vtkm::IdComponent cellSize)
281  : CellSize(cellSize)
282  {
283  }
284 
285  VTKM_EXEC
286  vtkm::Id operator()(vtkm::Id inIdx) const { return inIdx / this->CellSize; }
287 };
288 
289 template <typename ConnTableT, typename RConnTableT>
290 void ComputeRConnTable(RConnTableT& rConnTable,
291  const ConnTableT& connTable,
292  vtkm::Id numberOfPoints,
294 {
295  if (rConnTable.ElementsValid)
296  {
297  return;
298  }
299 
300  const auto& conn = connTable.Connectivity;
301  auto& rConn = rConnTable.Connectivity;
302  auto& rOffsets = rConnTable.Offsets;
303  const vtkm::Id rConnSize = conn.GetNumberOfValues();
304 
305  {
306  vtkm::cont::Token token;
307  const auto offInPortal = connTable.Offsets.PrepareForInput(device, token);
308 
309  PassThrough idxCalc{};
310  ConnIdxToCellIdCalc<decltype(offInPortal)> cellIdCalc{ offInPortal };
311 
312  vtkm::cont::internal::ReverseConnectivityBuilder builder;
313  builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, device);
314  }
315 
316  rConnTable.Shapes = vtkm::cont::make_ArrayHandleConstant(
317  static_cast<vtkm::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
318  rConnTable.ElementsValid = true;
319 }
320 
321 // Specialize for CellSetSingleType:
322 template <typename RConnTableT, typename ConnectivityStorageTag>
323 void ComputeRConnTable(RConnTableT& rConnTable,
324  const ConnectivityExplicitInternals< // SingleType specialization types:
326  ConnectivityStorageTag,
328  vtkm::Id numberOfPoints,
330 {
331  if (rConnTable.ElementsValid)
332  {
333  return;
334  }
335 
336  const auto& conn = connTable.Connectivity;
337  auto& rConn = rConnTable.Connectivity;
338  auto& rOffsets = rConnTable.Offsets;
339  const vtkm::Id rConnSize = conn.GetNumberOfValues();
340 
341  const vtkm::IdComponent cellSize = [&]() -> vtkm::IdComponent {
342  if (connTable.Offsets.GetNumberOfValues() >= 2)
343  {
344  const auto firstTwo = vtkm::cont::ArrayGetValues({ 0, 1 }, connTable.Offsets);
345  return static_cast<vtkm::IdComponent>(firstTwo[1] - firstTwo[0]);
346  }
347  return 0;
348  }();
349 
350  PassThrough idxCalc{};
351  ConnIdxToCellIdCalcSingleType cellIdCalc{ cellSize };
352 
353  vtkm::cont::internal::ReverseConnectivityBuilder builder;
354  builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, device);
355 
356  rConnTable.Shapes = vtkm::cont::make_ArrayHandleConstant(
357  static_cast<vtkm::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
358  rConnTable.ElementsValid = true;
359 }
360 
361 }
362 }
363 } // end namespace vtkm::cont::internal
364 
365 #endif // ReverseConnectivityBuilder_h
vtkm::cont::ArrayHandle< vtkm::IdComponent >
ArrayHandle.h
VTKM_EXEC
#define VTKM_EXEC
Definition: ExportMacros.h:51
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
ArrayHandleCast.h
CellSetExplicit.h
vtkm::IdComponent
vtkm::Int32 IdComponent
Represents a component ID (index of component in a vector).
Definition: Types.h:168
vtkm::cont::ArrayGetValues
VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle< vtkm::Id, SIds > &ids, const vtkm::cont::ArrayHandle< T, SData > &data, vtkm::cont::ArrayHandle< T, SOut > &output)
Obtain a small set of values from an ArrayHandle with minimal device transfers.
Definition: ArrayGetValues.h:119
vtkm::cont::make_ArrayHandleConstant
vtkm::cont::ArrayHandleConstant< T > make_ArrayHandleConstant(T value, vtkm::Id numberOfValues)
make_ArrayHandleConstant is convenience function to generate an ArrayHandleImplicit.
Definition: ArrayHandleConstant.h:89
ArrayHandleConstant.h
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
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
vtkm::cont::StorageTagConstant
Definition: ArrayHandleConstant.h:20
vtkm::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:35
vtkm::cont::StorageTagCounting
Definition: ArrayHandleCounting.h:23
vtkm::cont::Algorithm::Schedule
static VTKM_CONT void Schedule(vtkm::cont::DeviceAdapterId devId, Functor functor, vtkm::Id numInstances)
Definition: Algorithm.h:937
Algorithm.h
FunctorBase.h
VTKM_CONT
#define VTKM_CONT
Definition: ExportMacros.h:57
vtkm::UInt8
uint8_t UInt8
Definition: Types.h:157
vtkm::exec::FunctorBase
Base class for all user worklets invoked in the execution environment from a call to vtkm::cont::Devi...
Definition: FunctorBase.h:30
vtkm::cont::DeviceAdapterId
Definition: DeviceAdapterTag.h:52
vtkm::cont::Algorithm::ScanExtended
static VTKM_CONT void ScanExtended(vtkm::cont::DeviceAdapterId devId, const vtkm::cont::ArrayHandle< T, CIn > &input, vtkm::cont::ArrayHandle< T, COut > &output)
Definition: Algorithm.h:901
vtkm::cont::AtomicArray
A type list containing types that can be used with an AtomicArray.
Definition: AtomicArray.h:49
vtkm::CELL_SHAPE_VERTEX
@ CELL_SHAPE_VERTEX
Definition: CellShape.h:37
AtomicArray.h