Viskores  1.0
ReverseConnectivityBuilder.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 #ifndef viskores_cont_internal_ReverseConnectivityBuilder_h
19 #define viskores_cont_internal_ReverseConnectivityBuilder_h
20 
26 
29 
30 #include <utility>
31 
32 namespace viskores
33 {
34 namespace cont
35 {
36 namespace internal
37 {
38 
39 namespace rcb
40 {
41 
42 template <typename AtomicHistogram, typename ConnInPortal, typename RConnToConnIdxCalc>
43 struct BuildHistogram : public viskores::exec::FunctorBase
44 {
45  AtomicHistogram Histo;
46  ConnInPortal Conn;
47  RConnToConnIdxCalc IdxCalc;
48 
50  BuildHistogram(const AtomicHistogram& histo,
51  const ConnInPortal& conn,
52  const RConnToConnIdxCalc& idxCalc)
53  : Histo(histo)
54  , Conn(conn)
55  , IdxCalc(idxCalc)
56  {
57  }
58 
60  void operator()(viskores::Id rconnIdx) const
61  {
62  // Compute the connectivity array index (skipping cell length entries)
63  const viskores::Id connIdx = this->IdxCalc(rconnIdx);
64  const viskores::Id ptId = this->Conn.Get(connIdx);
65  this->Histo.Add(ptId, 1);
66  }
67 };
68 
69 template <typename AtomicHistogram,
70  typename ConnInPortal,
71  typename ROffsetInPortal,
72  typename RConnOutPortal,
73  typename RConnToConnIdxCalc,
74  typename ConnIdxToCellIdxCalc>
75 struct GenerateRConn : public viskores::exec::FunctorBase
76 {
77  AtomicHistogram Histo;
78  ConnInPortal Conn;
79  ROffsetInPortal ROffsets;
80  RConnOutPortal RConn;
81  RConnToConnIdxCalc IdxCalc;
82  ConnIdxToCellIdxCalc CellIdCalc;
83 
85  GenerateRConn(const AtomicHistogram& histo,
86  const ConnInPortal& conn,
87  const ROffsetInPortal& rOffsets,
88  const RConnOutPortal& rconn,
89  const RConnToConnIdxCalc& idxCalc,
90  const ConnIdxToCellIdxCalc& cellIdCalc)
91  : Histo(histo)
92  , Conn(conn)
93  , ROffsets(rOffsets)
94  , RConn(rconn)
95  , IdxCalc(idxCalc)
96  , CellIdCalc(cellIdCalc)
97  {
98  }
99 
101  void operator()(viskores::Id inputIdx) const
102  {
103  // Compute the connectivity array index (skipping cell length entries)
104  const viskores::Id connIdx = this->IdxCalc(inputIdx);
105  const viskores::Id ptId = this->Conn.Get(connIdx);
106 
107  // Compute the cell id:
108  const viskores::Id cellId = this->CellIdCalc(connIdx);
109 
110  // Find the base offset for this point id:
111  const viskores::Id baseOffset = this->ROffsets.Get(ptId);
112 
113  // Find the next unused index for this point id
114  const viskores::Id nextAvailable = this->Histo.Add(ptId, 1);
115 
116  // Update the final location in the RConn table with the cellId
117  const viskores::Id rconnIdx = baseOffset + nextAvailable;
118  this->RConn.Set(rconnIdx, cellId);
119  }
120 };
121 }
137 class ReverseConnectivityBuilder
138 {
139 public:
141  template <typename ConnArray,
142  typename RConnArray,
143  typename ROffsetsArray,
144  typename RConnToConnIdxCalc,
145  typename ConnIdxToCellIdxCalc>
146  inline void Run(const ConnArray& conn,
147  RConnArray& rConn,
148  ROffsetsArray& rOffsets,
149  const RConnToConnIdxCalc& rConnToConnCalc,
150  const ConnIdxToCellIdxCalc& cellIdCalc,
151  viskores::Id numberOfPoints,
152  viskores::Id rConnSize,
154  {
155  viskores::cont::Token connToken;
156  auto connPortal = conn.PrepareForInput(device, connToken);
157  auto zeros =
159 
160  // Compute RConn offsets by atomically building a histogram and doing an
161  // extended scan.
162  //
163  // Example:
164  // (in) Conn: | 3 0 1 2 | 3 0 1 3 | 3 0 3 4 | 3 3 4 5 |
165  // (out) RNumIndices: 3 2 1 3 2 1
166  // (out) RIdxOffsets: 0 3 5 6 9 11 12
168  { // allocate and zero the numIndices array:
169  viskores::cont::Algorithm::Copy(device, zeros, rNumIndices);
170  }
171 
172  { // Build histogram:
173  viskores::cont::AtomicArray<viskores::IdComponent> atomicCounter{ rNumIndices };
174  viskores::cont::Token token;
175  auto ac = atomicCounter.PrepareForExecution(device, token);
176  using BuildHisto =
177  rcb::BuildHistogram<decltype(ac), decltype(connPortal), RConnToConnIdxCalc>;
178  BuildHisto histoGen{ ac, connPortal, rConnToConnCalc };
179 
180  viskores::cont::Algorithm::Schedule(device, histoGen, rConnSize);
181  }
182 
183  { // Compute offsets:
185  device, viskores::cont::make_ArrayHandleCast<viskores::Id>(rNumIndices), rOffsets);
186  }
187 
188  { // Reset the numIndices array to 0's:
189  viskores::cont::Algorithm::Copy(device, zeros, rNumIndices);
190  }
191 
192  // Fill the connectivity table:
193  // 1) Lookup each point idx base offset.
194  // 2) Use the atomic histogram to find the next available slot for this
195  // pt id in RConn.
196  // 3) Compute the cell id from the connectivity index
197  // 4) Update RConn[nextSlot] = cellId
198  //
199  // Example:
200  // (in) Conn: | 3 0 1 2 | 3 0 1 3 | 3 0 3 4 | 3 3 4 5 |
201  // (inout) RNumIndices: 0 0 0 0 0 0 (Initial)
202  // (inout) RNumIndices: 3 2 1 3 2 1 (Final)
203  // (in) RIdxOffsets: 0 3 5 6 9 11
204  // (out) RConn: | 0 1 2 | 0 1 | 0 | 1 2 3 | 2 3 | 3 |
205  {
206  viskores::cont::AtomicArray<viskores::IdComponent> atomicCounter{ rNumIndices };
207  viskores::cont::Token token;
208  auto ac = atomicCounter.PrepareForExecution(device, token);
209  auto rOffsetPortal = rOffsets.PrepareForInput(device, token);
210  auto rConnPortal = rConn.PrepareForOutput(rConnSize, device, token);
211 
212  using GenRConnT = rcb::GenerateRConn<decltype(ac),
213  decltype(connPortal),
214  decltype(rOffsetPortal),
215  decltype(rConnPortal),
216  RConnToConnIdxCalc,
217  ConnIdxToCellIdxCalc>;
218  GenRConnT rConnGen{ ac, connPortal, rOffsetPortal, rConnPortal, rConnToConnCalc, cellIdCalc };
219 
220  viskores::cont::Algorithm::Schedule(device, rConnGen, rConnSize);
221  }
222  }
223 };
224 
225 // Pass through (needed for ReverseConnectivityBuilder)
226 struct PassThrough
227 {
228  VISKORES_EXEC viskores::Id operator()(const viskores::Id& val) const { return val; }
229 };
230 
231 // Compute cell id from input connectivity:
232 // Find the upper bound of the conn idx in the offsets table and subtract 1
233 //
234 // Example:
235 // Offsets: | 0 | 3 | 6 | 10 |
236 // Conn: | 0 1 2 | 0 1 3 | 2 4 5 6 | 1 3 5 |
237 // ConnIdx: | 0 1 2 | 3 4 5 | 6 7 8 9 | 10 11 12 |
238 // UpprBnd: | 1 1 1 | 2 2 2 | 3 3 3 3 | 4 4 4 |
239 // CellIdx: | 0 0 0 | 1 1 1 | 2 2 2 2 | 3 3 3 |
240 template <typename OffsetsPortalType>
241 struct ConnIdxToCellIdCalc
242 {
243  OffsetsPortalType Offsets;
244 
246  ConnIdxToCellIdCalc(const OffsetsPortalType& offsets)
247  : Offsets(offsets)
248  {
249  }
250 
252  viskores::Id operator()(viskores::Id inIdx) const
253  {
254  // Compute the upper bound index:
255  viskores::Id upperBoundIdx;
256  {
257  viskores::Id first = 0;
258  viskores::Id length = this->Offsets.GetNumberOfValues();
259 
260  while (length > 0)
261  {
262  viskores::Id halfway = length / 2;
263  viskores::Id pos = first + halfway;
264  viskores::Id val = this->Offsets.Get(pos);
265  if (val <= inIdx)
266  {
267  first = pos + 1;
268  length -= halfway + 1;
269  }
270  else
271  {
272  length = halfway;
273  }
274  }
275 
276  upperBoundIdx = first;
277  }
278 
279  return upperBoundIdx - 1;
280  }
281 };
282 
283 // Much easier for CellSetSingleType:
284 struct ConnIdxToCellIdCalcSingleType
285 {
286  viskores::IdComponent CellSize;
287 
289  ConnIdxToCellIdCalcSingleType(viskores::IdComponent cellSize)
290  : CellSize(cellSize)
291  {
292  }
293 
295  viskores::Id operator()(viskores::Id inIdx) const { return inIdx / this->CellSize; }
296 };
297 
298 template <typename ConnTableT, typename RConnTableT>
299 void ComputeRConnTable(RConnTableT& rConnTable,
300  const ConnTableT& connTable,
301  viskores::Id numberOfPoints,
303 {
304  if (rConnTable.ElementsValid)
305  {
306  return;
307  }
308 
309  const auto& conn = connTable.Connectivity;
310  auto& rConn = rConnTable.Connectivity;
311  auto& rOffsets = rConnTable.Offsets;
312  const viskores::Id rConnSize = conn.GetNumberOfValues();
313 
314  {
315  viskores::cont::Token token;
316  const auto offInPortal = connTable.Offsets.PrepareForInput(device, token);
317 
318  PassThrough idxCalc{};
319  ConnIdxToCellIdCalc<decltype(offInPortal)> cellIdCalc{ offInPortal };
320 
321  viskores::cont::internal::ReverseConnectivityBuilder builder;
322  builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, device);
323  }
324 
325  rConnTable.Shapes = viskores::cont::make_ArrayHandleConstant(
326  static_cast<viskores::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
327  rConnTable.ElementsValid = true;
328 }
329 
330 // Specialize for CellSetSingleType:
331 template <typename RConnTableT, typename ConnectivityStorageTag>
332 void ComputeRConnTable(
333  RConnTableT& rConnTable,
334  const ConnectivityExplicitInternals< // SingleType specialization types:
336  ConnectivityStorageTag,
338  viskores::Id numberOfPoints,
340 {
341  if (rConnTable.ElementsValid)
342  {
343  return;
344  }
345 
346  const auto& conn = connTable.Connectivity;
347  auto& rConn = rConnTable.Connectivity;
348  auto& rOffsets = rConnTable.Offsets;
349  const viskores::Id rConnSize = conn.GetNumberOfValues();
350 
351  const viskores::IdComponent cellSize = [&]() -> viskores::IdComponent
352  {
353  if (connTable.Offsets.GetNumberOfValues() >= 2)
354  {
355  const auto firstTwo = viskores::cont::ArrayGetValues({ 0, 1 }, connTable.Offsets);
356  return static_cast<viskores::IdComponent>(firstTwo[1] - firstTwo[0]);
357  }
358  return 0;
359  }();
360 
361  PassThrough idxCalc{};
362  ConnIdxToCellIdCalcSingleType cellIdCalc{ cellSize };
363 
364  viskores::cont::internal::ReverseConnectivityBuilder builder;
365  builder.Run(conn, rConn, rOffsets, idxCalc, cellIdCalc, numberOfPoints, rConnSize, device);
366 
367  rConnTable.Shapes = viskores::cont::make_ArrayHandleConstant(
368  static_cast<viskores::UInt8>(CELL_SHAPE_VERTEX), numberOfPoints);
369  rConnTable.ElementsValid = true;
370 }
371 
372 }
373 }
374 } // end namespace viskores::cont::internal
375 
376 #endif // ReverseConnectivityBuilder_h
viskores::cont::Algorithm::Schedule
static void Schedule(viskores::cont::DeviceAdapterId devId, Functor functor, viskores::Id numInstances)
Definition: Algorithm.h:957
ArrayHandle.h
viskores::exec::FunctorBase
Base class for all user worklets invoked in the execution environment from a call to viskores::cont::...
Definition: FunctorBase.h:38
ArrayHandleCast.h
CellSetExplicit.h
viskores::cont::ArrayHandle< viskores::IdComponent >
ArrayHandleConstant.h
viskores::IdComponent
viskores::Int32 IdComponent
Base type to use to index small lists.
Definition: Types.h:202
viskores::cont::AtomicArray
A type list containing types that can be used with an AtomicArray.
Definition: AtomicArray.h:61
viskores::cont::make_ArrayHandleConstant
viskores::cont::ArrayHandleConstant< T > make_ArrayHandleConstant(T value, viskores::Id numberOfValues)
make_ArrayHandleConstant is convenience function to generate an ArrayHandleImplicit.
Definition: ArrayHandleConstant.h:105
viskores::cont::ArrayHandleConstant::StorageTag
typename Superclass::StorageTag StorageTag
Definition: ArrayHandleConstant.h:85
viskores::cont::Algorithm::Copy
static bool Copy(viskores::cont::DeviceAdapterId devId, const viskores::cont::ArrayHandle< T, CIn > &input, viskores::cont::ArrayHandle< U, COut > &output)
Definition: Algorithm.h:422
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
Algorithm.h
FunctorBase.h
viskores::cont::Algorithm::ScanExtended
static void ScanExtended(viskores::cont::DeviceAdapterId devId, const viskores::cont::ArrayHandle< T, CIn > &input, viskores::cont::ArrayHandle< T, COut > &output)
Definition: Algorithm.h:921
viskores::cont::ArrayGetValues
void ArrayGetValues(const viskores::cont::ArrayHandle< viskores::Id, SIds > &ids, const viskores::cont::ArrayHandle< T, SData > &data, viskores::cont::ArrayHandle< T, SOut > &output)
Obtain a small set of values from an ArrayHandle with minimal device transfers.
Definition: ArrayGetValues.h:127
viskores::UInt8
uint8_t UInt8
Base type to use for 8-bit unsigned integer numbers.
Definition: Types.h:177
viskores::cont::DeviceAdapterId
An object used to specify a device.
Definition: DeviceAdapterTag.h:66
viskores::CELL_SHAPE_VERTEX
@ CELL_SHAPE_VERTEX
Vertex cells of a single point.
Definition: CellShape.h:47
viskores::cont::ArrayHandleCounting::StorageTag
typename Superclass::StorageTag StorageTag
Definition: ArrayHandleCounting.h:147
viskores::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:43
VISKORES_EXEC
#define VISKORES_EXEC
Definition: ExportMacros.h:59
AtomicArray.h