VTK-m  2.0
FunctorsGeneral.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_FunctorsGeneral_h
11 #define vtk_m_cont_internal_FunctorsGeneral_h
12 
13 #include <vtkm/BinaryOperators.h>
14 #include <vtkm/BinaryPredicates.h>
15 #include <vtkm/LowerBound.h>
16 #include <vtkm/TypeTraits.h>
17 #include <vtkm/UnaryPredicates.h>
18 #include <vtkm/UpperBound.h>
20 
21 #include <vtkm/exec/FunctorBase.h>
22 
23 #include <algorithm>
24 #include <atomic>
25 #include <iterator>
26 
27 namespace vtkm
28 {
29 namespace cont
30 {
31 namespace internal
32 {
33 
34 // Binary function object wrapper which can detect and handle calling the
35 // wrapped operator with complex value types such as
36 // ArrayPortalValueReference which happen when passed an input array that
37 // is implicit.
38 template <typename ResultType, typename Function>
39 struct WrappedBinaryOperator
40 {
41  Function m_f;
42 
43  VTKM_CONT
44  WrappedBinaryOperator(const Function& f)
45  : m_f(f)
46  {
47  }
48 
50  template <typename Argument1, typename Argument2>
51  VTKM_EXEC_CONT ResultType operator()(const Argument1& x, const Argument2& y) const
52  {
53  return static_cast<ResultType>(m_f(x, y));
54  }
55 
57  template <typename Argument1, typename Argument2>
58  VTKM_EXEC_CONT ResultType
59  operator()(const vtkm::internal::ArrayPortalValueReference<Argument1>& x,
60  const vtkm::internal::ArrayPortalValueReference<Argument2>& y) const
61  {
62  using ValueTypeX = typename vtkm::internal::ArrayPortalValueReference<Argument1>::ValueType;
63  using ValueTypeY = typename vtkm::internal::ArrayPortalValueReference<Argument2>::ValueType;
64  return static_cast<ResultType>(m_f((ValueTypeX)x, (ValueTypeY)y));
65  }
66 
68  template <typename Argument1, typename Argument2>
69  VTKM_EXEC_CONT ResultType
70  operator()(const Argument1& x,
71  const vtkm::internal::ArrayPortalValueReference<Argument2>& y) const
72  {
73  using ValueTypeY = typename vtkm::internal::ArrayPortalValueReference<Argument2>::ValueType;
74  return static_cast<ResultType>(m_f(x, (ValueTypeY)y));
75  }
76 
78  template <typename Argument1, typename Argument2>
79  VTKM_EXEC_CONT ResultType
80  operator()(const vtkm::internal::ArrayPortalValueReference<Argument1>& x,
81  const Argument2& y) const
82  {
83  using ValueTypeX = typename vtkm::internal::ArrayPortalValueReference<Argument1>::ValueType;
84  return static_cast<ResultType>(m_f((ValueTypeX)x, y));
85  }
86 };
87 
88 using DefaultCompareFunctor = vtkm::SortLess;
89 
90 //needs to be in a location that TBB DeviceAdapterAlgorithm can reach
91 template <typename T, typename U, class BinaryCompare = DefaultCompareFunctor>
92 struct KeyCompare
93 {
94  KeyCompare()
95  : CompareFunctor()
96  {
97  }
98  explicit KeyCompare(BinaryCompare c)
99  : CompareFunctor(c)
100  {
101  }
102 
104  VTKM_EXEC
105  bool operator()(const vtkm::Pair<T, U>& a, const vtkm::Pair<T, U>& b) const
106  {
107  return CompareFunctor(a.first, b.first);
108  }
109 
110 private:
111  BinaryCompare CompareFunctor;
112 };
113 
114 template <typename PortalConstType, typename T, typename BinaryFunctor>
115 struct ReduceKernel : vtkm::exec::FunctorBase
116 {
117  PortalConstType Portal;
118  T InitialValue;
119  BinaryFunctor BinaryOperator;
120  vtkm::Id PortalLength;
121 
123  ReduceKernel()
124  : Portal()
125  , InitialValue()
126  , BinaryOperator()
127  , PortalLength(0)
128  {
129  }
130 
131  VTKM_CONT
132  ReduceKernel(const PortalConstType& portal, T initialValue, BinaryFunctor binary_functor)
133  : Portal(portal)
134  , InitialValue(initialValue)
135  , BinaryOperator(binary_functor)
136  , PortalLength(portal.GetNumberOfValues())
137  {
138  }
139 
141  VTKM_EXEC
142  T operator()(vtkm::Id index) const
143  {
144  const vtkm::Id reduceWidth = 16;
145  const vtkm::Id offset = index * reduceWidth;
146 
147  if (offset + reduceWidth >= this->PortalLength)
148  {
149  //This will only occur for a single index value, so this is the case
150  //that needs to handle the initialValue
151  T partialSum = static_cast<T>(BinaryOperator(this->InitialValue, this->Portal.Get(offset)));
152  vtkm::Id currentIndex = offset + 1;
153  while (currentIndex < this->PortalLength)
154  {
155  partialSum = static_cast<T>(BinaryOperator(partialSum, this->Portal.Get(currentIndex)));
156  ++currentIndex;
157  }
158  return partialSum;
159  }
160  else
161  {
162  //optimize the usecase where all values are valid and we don't
163  //need to check that we might go out of bounds
164  T partialSum =
165  static_cast<T>(BinaryOperator(this->Portal.Get(offset), this->Portal.Get(offset + 1)));
166  for (int i = 2; i < reduceWidth; ++i)
167  {
168  partialSum = static_cast<T>(BinaryOperator(partialSum, this->Portal.Get(offset + i)));
169  }
170  return partialSum;
171  }
172  }
173 };
174 
175 struct ReduceKeySeriesStates
176 {
177  bool fStart; // START of a segment
178  bool fEnd; // END of a segment
179 
181  VTKM_EXEC
182  ReduceKeySeriesStates(bool start = false, bool end = false)
183  : fStart(start)
184  , fEnd(end)
185  {
186  }
187 };
188 
189 template <typename InputPortalType, typename KeyStatePortalType>
190 struct ReduceStencilGeneration : vtkm::exec::FunctorBase
191 {
192  InputPortalType Input;
193  KeyStatePortalType KeyState;
194 
195  VTKM_CONT
196  ReduceStencilGeneration(const InputPortalType& input, const KeyStatePortalType& kstate)
197  : Input(input)
198  , KeyState(kstate)
199  {
200  }
201 
203  VTKM_EXEC
204  void operator()(vtkm::Id centerIndex) const
205  {
206  using ValueType = typename InputPortalType::ValueType;
207  using KeyStateType = typename KeyStatePortalType::ValueType;
208 
209  const vtkm::Id leftIndex = centerIndex - 1;
210  const vtkm::Id rightIndex = centerIndex + 1;
211 
212  //we need to determine which of three states this
213  //index is. It can be:
214  // 1. Middle of a set of equivalent keys.
215  // 2. Start of a set of equivalent keys.
216  // 3. End of a set of equivalent keys.
217  // 4. Both the start and end of a set of keys
218 
219  //we don't have to worry about an array of length 1, as
220  //the calling code handles that use case
221 
222  if (centerIndex == 0)
223  {
224  //this means we are at the start of the array
225  //means we are automatically START
226  //just need to check if we are END
227  const ValueType centerValue = this->Input.Get(centerIndex);
228  const ValueType rightValue = this->Input.Get(rightIndex);
229  const KeyStateType state = ReduceKeySeriesStates(true, rightValue != centerValue);
230  this->KeyState.Set(centerIndex, state);
231  }
232  else if (rightIndex == this->Input.GetNumberOfValues())
233  {
234  //this means we are at the end, so we are at least END
235  //just need to check if we are START
236  const ValueType centerValue = this->Input.Get(centerIndex);
237  const ValueType leftValue = this->Input.Get(leftIndex);
238  const KeyStateType state = ReduceKeySeriesStates(leftValue != centerValue, true);
239  this->KeyState.Set(centerIndex, state);
240  }
241  else
242  {
243  const ValueType centerValue = this->Input.Get(centerIndex);
244  const bool leftMatches(this->Input.Get(leftIndex) == centerValue);
245  const bool rightMatches(this->Input.Get(rightIndex) == centerValue);
246 
247  //assume it is the middle, and check for the other use-case
248  KeyStateType state = ReduceKeySeriesStates(!leftMatches, !rightMatches);
249  this->KeyState.Set(centerIndex, state);
250  }
251  }
252 };
253 
254 template <typename BinaryFunctor>
255 struct ReduceByKeyAdd
256 {
257  BinaryFunctor BinaryOperator;
258 
259  ReduceByKeyAdd(BinaryFunctor binary_functor)
260  : BinaryOperator(binary_functor)
261  {
262  }
263 
264  template <typename T>
268  {
269  using ReturnType = vtkm::Pair<T, ReduceKeySeriesStates>;
270  //need too handle how we are going to add two numbers together
271  //based on the keyStates that they have
272 
273  // Make it work for parallel inclusive scan. Will end up with all start bits = 1
274  // the following logic should change if you use a different parallel scan algorithm.
275  if (!b.second.fStart)
276  {
277  // if b is not START, then it's safe to sum a & b.
278  // Propagate a's start flag to b
279  // so that later when b's START bit is set, it means there must exists a START between a and b
280  return ReturnType(this->BinaryOperator(a.first, b.first),
281  ReduceKeySeriesStates(a.second.fStart, b.second.fEnd));
282  }
283  return b;
284  }
285 };
286 
287 struct ReduceByKeyUnaryStencilOp
288 {
289  VTKM_EXEC
290  bool operator()(ReduceKeySeriesStates keySeriesState) const { return keySeriesState.fEnd; }
291 };
292 
293 template <typename T,
294  typename InputPortalType,
295  typename KeyStatePortalType,
296  typename OutputPortalType>
297 struct ShiftCopyAndInit : vtkm::exec::FunctorBase
298 {
299  InputPortalType Input;
300  KeyStatePortalType KeyState;
301  OutputPortalType Output;
302  T initValue;
303 
304  ShiftCopyAndInit(const InputPortalType& _input,
305  const KeyStatePortalType& kstate,
306  OutputPortalType& _output,
307  T _init)
308  : Input(_input)
309  , KeyState(kstate)
310  , Output(_output)
311  , initValue(_init)
312  {
313  }
314 
315  VTKM_EXEC
316  void operator()(vtkm::Id index) const
317  {
318  if (this->KeyState.Get(index).fStart)
319  {
320  Output.Set(index, initValue);
321  }
322  else
323  {
324  Output.Set(index, Input.Get(index - 1));
325  }
326  }
327 };
328 
329 template <class BitsPortal, class IndicesPortal>
330 struct BitFieldToUnorderedSetFunctor : public vtkm::exec::FunctorBase
331 {
332  using WordType = typename BitsPortal::WordTypePreferred;
333 
334  // This functor executes a number of instances, where each instance handles
335  // two cachelines worth of data. Figure out how many words that is:
336  static constexpr vtkm::Id CacheLineSize = VTKM_ALLOCATION_ALIGNMENT;
337  static constexpr vtkm::Id WordsPerCacheLine =
338  CacheLineSize / static_cast<vtkm::Id>(sizeof(WordType));
339  static constexpr vtkm::Id CacheLinesPerInstance = 2;
340  static constexpr vtkm::Id WordsPerInstance = CacheLinesPerInstance * WordsPerCacheLine;
341 
343  VTKM_PASS_COMMAS(std::is_same<typename IndicesPortal::ValueType, vtkm::Id>::value));
344 
345  VTKM_CONT
346  BitFieldToUnorderedSetFunctor(const BitsPortal& input,
347  IndicesPortal& output,
348  std::atomic<vtkm::UInt64>& popCount)
349  : Input{ input }
350  , Output{ output }
351  , PopCount(popCount)
352  , FinalWordIndex{ input.GetNumberOfWords() - 1 }
353  , FinalWordMask(input.GetFinalWordMask())
354  {
355  }
356 
357  VTKM_CONT vtkm::Id GetNumberOfInstances() const
358  {
359  const auto numWords = this->Input.GetNumberOfWords();
360  return (numWords + WordsPerInstance - 1) / WordsPerInstance;
361  }
362 
363  VTKM_EXEC void operator()(vtkm::Id instanceIdx) const
364  {
365  const vtkm::Id numWords = this->Input.GetNumberOfWords();
366  const vtkm::Id wordStart = vtkm::Min(instanceIdx * WordsPerInstance, numWords);
367  const vtkm::Id wordEnd = vtkm::Min(wordStart + WordsPerInstance, numWords);
368 
369  if (wordStart != wordEnd) // range is valid
370  {
371  this->ExecuteRange(wordStart, wordEnd);
372  }
373  }
374 
375  VTKM_EXEC void ExecuteRange(vtkm::Id wordStart, vtkm::Id wordEnd) const
376  {
377 #ifndef VTKM_CUDA_DEVICE_PASS // for std::atomic call from VTKM_EXEC function:
378  // Count bits and allocate space for output:
379  vtkm::UInt64 chunkBits = this->CountChunkBits(wordStart, wordEnd);
380  if (chunkBits > 0)
381  {
382  vtkm::UInt64 outIdx = this->PopCount.fetch_add(chunkBits, std::memory_order_relaxed);
383 
384  this->ProcessWords(wordStart, wordEnd, static_cast<vtkm::Id>(outIdx));
385  }
386 #else
387  (void)wordStart;
388  (void)wordEnd;
389 #endif
390  }
391 
392  VTKM_CONT vtkm::UInt64 GetPopCount() const { return PopCount.load(std::memory_order_relaxed); }
393 
394 private:
395  VTKM_EXEC vtkm::UInt64 CountChunkBits(vtkm::Id wordStart, vtkm::Id wordEnd) const
396  {
397  // Need to mask out trailing bits from the final word:
398  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
399 
400  if (isFinalChunk)
401  {
402  wordEnd = this->FinalWordIndex;
403  }
404 
405  vtkm::Int32 tmp = 0;
406  for (vtkm::Id i = wordStart; i < wordEnd; ++i)
407  {
408  tmp += vtkm::CountSetBits(this->Input.GetWord(i));
409  }
410 
411  if (isFinalChunk)
412  {
413  tmp += vtkm::CountSetBits(this->Input.GetWord(this->FinalWordIndex) & this->FinalWordMask);
414  }
415 
416  return static_cast<vtkm::UInt64>(tmp);
417  }
418 
419  VTKM_EXEC void ProcessWords(vtkm::Id wordStart, vtkm::Id wordEnd, vtkm::Id outputStartIdx) const
420  {
421  // Need to mask out trailing bits from the final word:
422  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
423 
424  if (isFinalChunk)
425  {
426  wordEnd = this->FinalWordIndex;
427  }
428 
429  for (vtkm::Id i = wordStart; i < wordEnd; ++i)
430  {
431  const vtkm::Id firstBitIdx = i * static_cast<vtkm::Id>(sizeof(WordType)) * CHAR_BIT;
432  WordType word = this->Input.GetWord(i);
433  while (word != 0) // have bits
434  {
435  // Find next bit. FindFirstSetBit starts counting at 1.
436  vtkm::Int32 bit = vtkm::FindFirstSetBit(word) - 1;
437  this->Output.Set(outputStartIdx++, firstBitIdx + bit); // Write index of bit
438  word ^= (1 << bit); // clear bit
439  }
440  }
441 
442  if (isFinalChunk)
443  {
444  const vtkm::Id i = this->FinalWordIndex;
445  const vtkm::Id firstBitIdx = i * static_cast<vtkm::Id>(sizeof(WordType)) * CHAR_BIT;
446  WordType word = this->Input.GetWord(i) & this->FinalWordMask;
447  while (word != 0) // have bits
448  {
449  // Find next bit. FindFirstSetBit starts counting at 1.
450  vtkm::Int32 bit = vtkm::FindFirstSetBit(word) - 1;
451  this->Output.Set(outputStartIdx++, firstBitIdx + bit); // Write index of bit
452  word ^= (1 << bit); // clear bit
453  }
454  }
455  }
456 
457  BitsPortal Input;
458  IndicesPortal Output;
459  std::atomic<vtkm::UInt64>& PopCount;
460  // Used to mask trailing bits the in last word.
461  vtkm::Id FinalWordIndex{ 0 };
462  WordType FinalWordMask{ 0 };
463 };
464 
465 template <class InputPortalType, class OutputPortalType>
466 struct CopyKernel
467 {
468  InputPortalType InputPortal;
469  OutputPortalType OutputPortal;
470  vtkm::Id InputOffset;
471  vtkm::Id OutputOffset;
472 
473  VTKM_CONT
474  CopyKernel(InputPortalType inputPortal,
475  OutputPortalType outputPortal,
476  vtkm::Id inputOffset = 0,
477  vtkm::Id outputOffset = 0)
478  : InputPortal(inputPortal)
479  , OutputPortal(outputPortal)
480  , InputOffset(inputOffset)
481  , OutputOffset(outputOffset)
482  {
483  }
484 
485  VTKM_EXEC
486  void operator()(vtkm::Id index) const
487  {
488  using ValueType = typename OutputPortalType::ValueType;
489  this->OutputPortal.Set(
490  index + this->OutputOffset,
491  static_cast<ValueType>(this->InputPortal.Get(index + this->InputOffset)));
492  }
493 
494  VTKM_CONT
495  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
496 };
497 
498 template <typename BitsPortal>
499 struct CountSetBitsFunctor : public vtkm::exec::FunctorBase
500 {
501  using WordType = typename BitsPortal::WordTypePreferred;
502 
503  // This functor executes a number of instances, where each instance handles
504  // two cachelines worth of data. This reduces the number of atomic operations.
505  // Figure out how many words that is:
506  static constexpr vtkm::Id CacheLineSize = VTKM_ALLOCATION_ALIGNMENT;
507  static constexpr vtkm::Id WordsPerCacheLine =
508  CacheLineSize / static_cast<vtkm::Id>(sizeof(WordType));
509  static constexpr vtkm::Id CacheLinesPerInstance = 2;
510  static constexpr vtkm::Id WordsPerInstance = CacheLinesPerInstance * WordsPerCacheLine;
511 
512  VTKM_CONT
513  CountSetBitsFunctor(const BitsPortal& input, std::atomic<vtkm::UInt64>& popCount)
514  : Input{ input }
515  , PopCount(popCount)
516  , FinalWordIndex{ input.GetNumberOfWords() - 1 }
517  , FinalWordMask{ input.GetFinalWordMask() }
518  {
519  }
520 
521  VTKM_CONT vtkm::Id GetNumberOfInstances() const
522  {
523  const auto numWords = this->Input.GetNumberOfWords();
524  return (numWords + WordsPerInstance - 1) / WordsPerInstance;
525  }
526 
527  VTKM_EXEC void operator()(vtkm::Id instanceIdx) const
528  {
529  const vtkm::Id numWords = this->Input.GetNumberOfWords();
530  const vtkm::Id wordStart = vtkm::Min(instanceIdx * WordsPerInstance, numWords);
531  const vtkm::Id wordEnd = vtkm::Min(wordStart + WordsPerInstance, numWords);
532 
533  if (wordStart != wordEnd) // range is valid
534  {
535  this->ExecuteRange(wordStart, wordEnd);
536  }
537  }
538 
539  VTKM_CONT vtkm::UInt64 GetPopCount() const { return PopCount.load(std::memory_order_relaxed); }
540 
541 private:
542  VTKM_EXEC void ExecuteRange(vtkm::Id wordStart, vtkm::Id wordEnd) const
543  {
544 #ifndef VTKM_CUDA_DEVICE_PASS // for std::atomic call from VTKM_EXEC function:
545  // Count bits and allocate space for output:
546  vtkm::UInt64 chunkBits = this->CountChunkBits(wordStart, wordEnd);
547  this->PopCount.fetch_add(chunkBits, std::memory_order_relaxed);
548 #else
549  (void)wordStart;
550  (void)wordEnd;
551 #endif
552  }
553 
554  VTKM_EXEC vtkm::UInt64 CountChunkBits(vtkm::Id wordStart, vtkm::Id wordEnd) const
555  {
556  // Need to mask out trailing bits from the final word:
557  const bool isFinalChunk = wordEnd == (this->FinalWordIndex + 1);
558 
559  if (isFinalChunk)
560  {
561  wordEnd = this->FinalWordIndex;
562  }
563 
564  vtkm::Int32 tmp = 0;
565  for (vtkm::Id i = wordStart; i < wordEnd; ++i)
566  {
567  tmp += vtkm::CountSetBits(this->Input.GetWord(i));
568  }
569 
570  if (isFinalChunk)
571  {
572  tmp += vtkm::CountSetBits(this->Input.GetWord(this->FinalWordIndex) & this->FinalWordMask);
573  }
574 
575  return static_cast<vtkm::UInt64>(tmp);
576  }
577 
578  BitsPortal Input;
579  std::atomic<vtkm::UInt64>& PopCount;
580  // Used to mask trailing bits the in last word.
581  vtkm::Id FinalWordIndex{ 0 };
582  WordType FinalWordMask{ 0 };
583 };
584 
585 // For a given unsigned integer less than 32 bits, repeat its bits until we
586 // have a 32 bit pattern. This is used to make all fill patterns at least
587 // 32 bits in size, since concurrently writing to adjacent locations smaller
588 // than 32 bits may race on some platforms.
589 template <typename WordType, typename = typename std::enable_if<(sizeof(WordType) >= 4)>::type>
590 static constexpr VTKM_CONT WordType RepeatTo32BitsIfNeeded(WordType pattern)
591 { // for 32 bits or more, just pass the type through.
592  return pattern;
593 }
594 
595 static inline constexpr VTKM_CONT vtkm::UInt32 RepeatTo32BitsIfNeeded(vtkm::UInt16 pattern)
596 {
597  return static_cast<vtkm::UInt32>(pattern << 16 | pattern);
598 }
599 
600 static inline constexpr VTKM_CONT vtkm::UInt32 RepeatTo32BitsIfNeeded(vtkm::UInt8 pattern)
601 {
602  return RepeatTo32BitsIfNeeded(static_cast<vtkm::UInt16>(pattern << 8 | pattern));
603 }
604 
605 template <typename BitsPortal, typename WordType>
606 struct FillBitFieldFunctor : public vtkm::exec::FunctorBase
607 {
608  VTKM_CONT
609  FillBitFieldFunctor(const BitsPortal& portal, WordType mask)
610  : Portal{ portal }
611  , Mask{ mask }
612  {
613  }
614 
615  VTKM_EXEC void operator()(vtkm::Id wordIdx) const { this->Portal.SetWord(wordIdx, this->Mask); }
616 
617 private:
618  BitsPortal Portal;
619  WordType Mask;
620 };
621 
622 template <typename PortalType>
623 struct FillArrayHandleFunctor : public vtkm::exec::FunctorBase
624 {
625  using ValueType = typename PortalType::ValueType;
626 
627  VTKM_CONT
628  FillArrayHandleFunctor(const PortalType& portal, ValueType value)
629  : Portal{ portal }
630  , Value{ value }
631  {
632  }
633 
634  VTKM_EXEC void operator()(vtkm::Id idx) const { this->Portal.Set(idx, this->Value); }
635 
636 private:
637  PortalType Portal;
638  ValueType Value;
639 };
640 
641 template <typename Iterator, typename IteratorTag>
642 VTKM_EXEC static inline vtkm::Id IteratorDistanceImpl(const Iterator& from,
643  const Iterator& to,
644  IteratorTag)
645 {
646  vtkm::Id dist = 0;
647  for (auto it = from; it != to; ++it)
648  {
649  ++dist;
650  }
651  return dist;
652 }
653 
654 template <typename Iterator>
655 VTKM_EXEC static inline vtkm::Id IteratorDistanceImpl(const Iterator& from,
656  const Iterator& to,
657  std::random_access_iterator_tag)
658 {
659  return static_cast<vtkm::Id>(to - from);
660 }
661 
662 #if defined(VTKM_HIP)
663 
664 template <typename Iterator>
665 __host__ static inline vtkm::Id IteratorDistance(const Iterator& from, const Iterator& to)
666 {
667  return static_cast<vtkm::Id>(std::distance(from, to));
668 }
669 
670 template <typename Iterator>
671 __device__ static inline vtkm::Id IteratorDistance(const Iterator& from, const Iterator& to)
672 {
673  return IteratorDistanceImpl(
674  from, to, typename std::iterator_traits<Iterator>::iterator_category{});
675 }
676 
677 #else
678 
679 template <typename Iterator>
680 VTKM_EXEC static inline vtkm::Id IteratorDistance(const Iterator& from, const Iterator& to)
681 {
682 #ifndef VTKM_CUDA_DEVICE_PASS
683  return static_cast<vtkm::Id>(std::distance(from, to));
684 #else
685  return IteratorDistanceImpl(
686  from, to, typename std::iterator_traits<Iterator>::iterator_category{});
687 #endif
688 }
689 
690 #endif
691 
692 template <class InputPortalType, class ValuesPortalType, class OutputPortalType>
693 struct LowerBoundsKernel
694 {
695  InputPortalType InputPortal;
696  ValuesPortalType ValuesPortal;
697  OutputPortalType OutputPortal;
698 
699  VTKM_CONT
700  LowerBoundsKernel(InputPortalType inputPortal,
701  ValuesPortalType valuesPortal,
702  OutputPortalType outputPortal)
703  : InputPortal(inputPortal)
704  , ValuesPortal(valuesPortal)
705  , OutputPortal(outputPortal)
706  {
707  }
708 
710  VTKM_EXEC
711  void operator()(vtkm::Id index) const
712  {
713  // This method assumes that (1) InputPortalType can return working
714  // iterators in the execution environment and that (2) methods not
715  // specified with VTKM_EXEC (such as the STL algorithms) can be
716  // called from the execution environment. Neither one of these is
717  // necessarily true, but it is true for the current uses of this general
718  // function and I don't want to compete with STL if I don't have to.
719 
720  using InputIteratorsType = vtkm::cont::ArrayPortalToIterators<InputPortalType>;
721  InputIteratorsType inputIterators(this->InputPortal);
722  auto resultPos = vtkm::LowerBound(
723  inputIterators.GetBegin(), inputIterators.GetEnd(), this->ValuesPortal.Get(index));
724 
725  vtkm::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
726  this->OutputPortal.Set(index, resultIndex);
727  }
728 
729  VTKM_CONT
730  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
731 };
732 
733 template <class InputPortalType,
734  class ValuesPortalType,
735  class OutputPortalType,
736  class BinaryCompare>
737 struct LowerBoundsComparisonKernel
738 {
739  InputPortalType InputPortal;
740  ValuesPortalType ValuesPortal;
741  OutputPortalType OutputPortal;
742  BinaryCompare CompareFunctor;
743 
744  VTKM_CONT
745  LowerBoundsComparisonKernel(InputPortalType inputPortal,
746  ValuesPortalType valuesPortal,
747  OutputPortalType outputPortal,
748  BinaryCompare binary_compare)
749  : InputPortal(inputPortal)
750  , ValuesPortal(valuesPortal)
751  , OutputPortal(outputPortal)
752  , CompareFunctor(binary_compare)
753  {
754  }
755 
757  VTKM_EXEC
758  void operator()(vtkm::Id index) const
759  {
760  // This method assumes that (1) InputPortalType can return working
761  // iterators in the execution environment and that (2) methods not
762  // specified with VTKM_EXEC (such as the STL algorithms) can be
763  // called from the execution environment. Neither one of these is
764  // necessarily true, but it is true for the current uses of this general
765  // function and I don't want to compete with STL if I don't have to.
766 
767  using InputIteratorsType = vtkm::cont::ArrayPortalToIterators<InputPortalType>;
768  InputIteratorsType inputIterators(this->InputPortal);
769  auto resultPos = vtkm::LowerBound(inputIterators.GetBegin(),
770  inputIterators.GetEnd(),
771  this->ValuesPortal.Get(index),
772  this->CompareFunctor);
773 
774  vtkm::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
775  this->OutputPortal.Set(index, resultIndex);
776  }
777 
778  VTKM_CONT
779  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
780 };
781 
782 template <typename PortalType>
783 struct SetConstantKernel
784 {
785  using ValueType = typename PortalType::ValueType;
786  PortalType Portal;
787  ValueType Value;
788 
789  VTKM_CONT
790  SetConstantKernel(const PortalType& portal, ValueType value)
791  : Portal(portal)
792  , Value(value)
793  {
794  }
795 
797  VTKM_EXEC
798  void operator()(vtkm::Id index) const { this->Portal.Set(index, this->Value); }
799 
800  VTKM_CONT
801  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
802 };
803 
804 template <typename PortalType, typename BinaryCompare>
805 struct BitonicSortMergeKernel : vtkm::exec::FunctorBase
806 {
807  PortalType Portal;
808  BinaryCompare Compare;
809  vtkm::Id GroupSize;
810 
811  VTKM_CONT
812  BitonicSortMergeKernel(const PortalType& portal, const BinaryCompare& compare, vtkm::Id groupSize)
813  : Portal(portal)
814  , Compare(compare)
815  , GroupSize(groupSize)
816  {
817  }
818 
820  VTKM_EXEC
821  void operator()(vtkm::Id index) const
822  {
823  using ValueType = typename PortalType::ValueType;
824 
825  vtkm::Id groupIndex = index % this->GroupSize;
826  vtkm::Id blockSize = 2 * this->GroupSize;
827  vtkm::Id blockIndex = index / this->GroupSize;
828 
829  vtkm::Id lowIndex = blockIndex * blockSize + groupIndex;
830  vtkm::Id highIndex = lowIndex + this->GroupSize;
831 
832  if (highIndex < this->Portal.GetNumberOfValues())
833  {
834  ValueType lowValue = this->Portal.Get(lowIndex);
835  ValueType highValue = this->Portal.Get(highIndex);
836  if (this->Compare(highValue, lowValue))
837  {
838  this->Portal.Set(highIndex, lowValue);
839  this->Portal.Set(lowIndex, highValue);
840  }
841  }
842  }
843 };
844 
845 template <typename PortalType, typename BinaryCompare>
846 struct BitonicSortCrossoverKernel : vtkm::exec::FunctorBase
847 {
848  PortalType Portal;
849  BinaryCompare Compare;
850  vtkm::Id GroupSize;
851 
852  VTKM_CONT
853  BitonicSortCrossoverKernel(const PortalType& portal,
854  const BinaryCompare& compare,
855  vtkm::Id groupSize)
856  : Portal(portal)
857  , Compare(compare)
858  , GroupSize(groupSize)
859  {
860  }
861 
863  VTKM_EXEC
864  void operator()(vtkm::Id index) const
865  {
866  using ValueType = typename PortalType::ValueType;
867 
868  vtkm::Id groupIndex = index % this->GroupSize;
869  vtkm::Id blockSize = 2 * this->GroupSize;
870  vtkm::Id blockIndex = index / this->GroupSize;
871 
872  vtkm::Id lowIndex = blockIndex * blockSize + groupIndex;
873  vtkm::Id highIndex = blockIndex * blockSize + (blockSize - groupIndex - 1);
874 
875  if (highIndex < this->Portal.GetNumberOfValues())
876  {
877  ValueType lowValue = this->Portal.Get(lowIndex);
878  ValueType highValue = this->Portal.Get(highIndex);
879  if (this->Compare(highValue, lowValue))
880  {
881  this->Portal.Set(highIndex, lowValue);
882  this->Portal.Set(lowIndex, highValue);
883  }
884  }
885  }
886 };
887 
888 template <class StencilPortalType, class OutputPortalType, class UnaryPredicate>
889 struct StencilToIndexFlagKernel
890 {
891  using StencilValueType = typename StencilPortalType::ValueType;
892  StencilPortalType StencilPortal;
893  OutputPortalType OutputPortal;
894  UnaryPredicate Predicate;
895 
896  VTKM_CONT
897  StencilToIndexFlagKernel(StencilPortalType stencilPortal,
898  OutputPortalType outputPortal,
899  UnaryPredicate unary_predicate)
900  : StencilPortal(stencilPortal)
901  , OutputPortal(outputPortal)
902  , Predicate(unary_predicate)
903  {
904  }
905 
907  VTKM_EXEC
908  void operator()(vtkm::Id index) const
909  {
910  StencilValueType value = this->StencilPortal.Get(index);
911  this->OutputPortal.Set(index, this->Predicate(value) ? 1 : 0);
912  }
913 
914  VTKM_CONT
915  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
916 };
917 
918 template <class InputPortalType,
919  class StencilPortalType,
920  class IndexPortalType,
921  class OutputPortalType,
922  class PredicateOperator>
923 struct CopyIfKernel
924 {
925  InputPortalType InputPortal;
926  StencilPortalType StencilPortal;
927  IndexPortalType IndexPortal;
928  OutputPortalType OutputPortal;
929  PredicateOperator Predicate;
930 
931  VTKM_CONT
932  CopyIfKernel(InputPortalType inputPortal,
933  StencilPortalType stencilPortal,
934  IndexPortalType indexPortal,
935  OutputPortalType outputPortal,
936  PredicateOperator unary_predicate)
937  : InputPortal(inputPortal)
938  , StencilPortal(stencilPortal)
939  , IndexPortal(indexPortal)
940  , OutputPortal(outputPortal)
941  , Predicate(unary_predicate)
942  {
943  }
944 
946  VTKM_EXEC
947  void operator()(vtkm::Id index) const
948  {
949  using StencilValueType = typename StencilPortalType::ValueType;
950  StencilValueType stencilValue = this->StencilPortal.Get(index);
951  if (Predicate(stencilValue))
952  {
953  vtkm::Id outputIndex = this->IndexPortal.Get(index);
954 
955  using OutputValueType = typename OutputPortalType::ValueType;
956  OutputValueType value = this->InputPortal.Get(index);
957 
958  this->OutputPortal.Set(outputIndex, value);
959  }
960  }
961 
962  VTKM_CONT
963  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
964 };
965 
966 template <class InputPortalType, class StencilPortalType>
967 struct ClassifyUniqueKernel
968 {
969  InputPortalType InputPortal;
970  StencilPortalType StencilPortal;
971 
972  VTKM_CONT
973  ClassifyUniqueKernel(InputPortalType inputPortal, StencilPortalType stencilPortal)
974  : InputPortal(inputPortal)
975  , StencilPortal(stencilPortal)
976  {
977  }
978 
980  VTKM_EXEC
981  void operator()(vtkm::Id index) const
982  {
983  using ValueType = typename StencilPortalType::ValueType;
984  if (index == 0)
985  {
986  // Always copy first value.
987  this->StencilPortal.Set(index, ValueType(1));
988  }
989  else
990  {
991  ValueType flag = ValueType(this->InputPortal.Get(index - 1) != this->InputPortal.Get(index));
992  this->StencilPortal.Set(index, flag);
993  }
994  }
995 
996  VTKM_CONT
997  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
998 };
999 
1000 template <class InputPortalType, class StencilPortalType, class BinaryCompare>
1001 struct ClassifyUniqueComparisonKernel
1002 {
1003  InputPortalType InputPortal;
1004  StencilPortalType StencilPortal;
1005  BinaryCompare CompareFunctor;
1006 
1007  VTKM_CONT
1008  ClassifyUniqueComparisonKernel(InputPortalType inputPortal,
1009  StencilPortalType stencilPortal,
1010  BinaryCompare binary_compare)
1011  : InputPortal(inputPortal)
1012  , StencilPortal(stencilPortal)
1013  , CompareFunctor(binary_compare)
1014  {
1015  }
1016 
1018  VTKM_EXEC
1019  void operator()(vtkm::Id index) const
1020  {
1021  using ValueType = typename StencilPortalType::ValueType;
1022  if (index == 0)
1023  {
1024  // Always copy first value.
1025  this->StencilPortal.Set(index, ValueType(1));
1026  }
1027  else
1028  {
1029  //comparison predicate returns true when they match
1030  const bool same =
1031  !(this->CompareFunctor(this->InputPortal.Get(index - 1), this->InputPortal.Get(index)));
1032  ValueType flag = ValueType(same);
1033  this->StencilPortal.Set(index, flag);
1034  }
1035  }
1036 
1037  VTKM_CONT
1038  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
1039 };
1040 
1041 template <class InputPortalType, class ValuesPortalType, class OutputPortalType>
1042 struct UpperBoundsKernel
1043 {
1044  InputPortalType InputPortal;
1045  ValuesPortalType ValuesPortal;
1046  OutputPortalType OutputPortal;
1047 
1048  VTKM_CONT
1049  UpperBoundsKernel(InputPortalType inputPortal,
1050  ValuesPortalType valuesPortal,
1051  OutputPortalType outputPortal)
1052  : InputPortal(inputPortal)
1053  , ValuesPortal(valuesPortal)
1054  , OutputPortal(outputPortal)
1055  {
1056  }
1057 
1059  VTKM_EXEC
1060  void operator()(vtkm::Id index) const
1061  {
1062  // This method assumes that (1) InputPortalType can return working
1063  // iterators in the execution environment and that (2) methods not
1064  // specified with VTKM_EXEC (such as the STL algorithms) can be
1065  // called from the execution environment. Neither one of these is
1066  // necessarily true, but it is true for the current uses of this general
1067  // function and I don't want to compete with STL if I don't have to.
1068 
1069  using InputIteratorsType = vtkm::cont::ArrayPortalToIterators<InputPortalType>;
1070  InputIteratorsType inputIterators(this->InputPortal);
1071  auto resultPos = vtkm::UpperBound(
1072  inputIterators.GetBegin(), inputIterators.GetEnd(), this->ValuesPortal.Get(index));
1073 
1074  vtkm::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
1075  this->OutputPortal.Set(index, resultIndex);
1076  }
1077 
1078  VTKM_CONT
1079  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
1080 };
1081 
1082 template <class InputPortalType,
1083  class ValuesPortalType,
1084  class OutputPortalType,
1085  class BinaryCompare>
1086 struct UpperBoundsKernelComparisonKernel
1087 {
1088  InputPortalType InputPortal;
1089  ValuesPortalType ValuesPortal;
1090  OutputPortalType OutputPortal;
1091  BinaryCompare CompareFunctor;
1092 
1093  VTKM_CONT
1094  UpperBoundsKernelComparisonKernel(InputPortalType inputPortal,
1095  ValuesPortalType valuesPortal,
1096  OutputPortalType outputPortal,
1097  BinaryCompare binary_compare)
1098  : InputPortal(inputPortal)
1099  , ValuesPortal(valuesPortal)
1100  , OutputPortal(outputPortal)
1101  , CompareFunctor(binary_compare)
1102  {
1103  }
1104 
1106  VTKM_EXEC
1107  void operator()(vtkm::Id index) const
1108  {
1109  // This method assumes that (1) InputPortalType can return working
1110  // iterators in the execution environment and that (2) methods not
1111  // specified with VTKM_EXEC (such as the STL algorithms) can be
1112  // called from the execution environment. Neither one of these is
1113  // necessarily true, but it is true for the current uses of this general
1114  // function and I don't want to compete with STL if I don't have to.
1115 
1116  using InputIteratorsType = vtkm::cont::ArrayPortalToIterators<InputPortalType>;
1117  InputIteratorsType inputIterators(this->InputPortal);
1118  auto resultPos = vtkm::UpperBound(inputIterators.GetBegin(),
1119  inputIterators.GetEnd(),
1120  this->ValuesPortal.Get(index),
1121  this->CompareFunctor);
1122 
1123  vtkm::Id resultIndex = IteratorDistance(inputIterators.GetBegin(), resultPos);
1124  this->OutputPortal.Set(index, resultIndex);
1125  }
1126 
1127  VTKM_CONT
1128  void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
1129 };
1130 
1131 template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
1132 struct InclusiveToExclusiveKernel : vtkm::exec::FunctorBase
1133 {
1134  using ValueType = typename InPortalType::ValueType;
1135 
1136  InPortalType InPortal;
1137  OutPortalType OutPortal;
1138  BinaryFunctor BinaryOperator;
1139  ValueType InitialValue;
1140 
1141  VTKM_CONT
1142  InclusiveToExclusiveKernel(const InPortalType& inPortal,
1143  const OutPortalType& outPortal,
1144  BinaryFunctor& binaryOperator,
1145  ValueType initialValue)
1146  : InPortal(inPortal)
1147  , OutPortal(outPortal)
1148  , BinaryOperator(binaryOperator)
1149  , InitialValue(initialValue)
1150  {
1151  }
1152 
1154  VTKM_EXEC
1155  void operator()(vtkm::Id index) const
1156  {
1157  const ValueType result = (index == 0)
1158  ? this->InitialValue
1159  : this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
1160 
1161  this->OutPortal.Set(index, result);
1162  }
1163 };
1164 
1165 template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
1166 struct InclusiveToExtendedKernel : vtkm::exec::FunctorBase
1167 {
1168  using ValueType = typename InPortalType::ValueType;
1169 
1170  InPortalType InPortal;
1171  OutPortalType OutPortal;
1172  BinaryFunctor BinaryOperator;
1173  ValueType InitialValue;
1174  ValueType FinalValue;
1175 
1176  VTKM_CONT
1177  InclusiveToExtendedKernel(const InPortalType& inPortal,
1178  const OutPortalType& outPortal,
1179  BinaryFunctor& binaryOperator,
1180  ValueType initialValue,
1181  ValueType finalValue)
1182  : InPortal(inPortal)
1183  , OutPortal(outPortal)
1184  , BinaryOperator(binaryOperator)
1185  , InitialValue(initialValue)
1186  , FinalValue(finalValue)
1187  {
1188  }
1189 
1191  VTKM_EXEC
1192  void operator()(vtkm::Id index) const
1193  {
1194  // The output array has one more value than the input, which holds the
1195  // total sum.
1196  const ValueType result = (index == 0) ? this->InitialValue
1197  : (index == this->InPortal.GetNumberOfValues())
1198  ? this->FinalValue
1199  : this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
1200 
1201  this->OutPortal.Set(index, result);
1202  }
1203 };
1204 
1205 template <typename PortalType, typename BinaryFunctor>
1206 struct ScanKernel : vtkm::exec::FunctorBase
1207 {
1208  PortalType Portal;
1209  BinaryFunctor BinaryOperator;
1210  vtkm::Id Stride;
1211  vtkm::Id Offset;
1212  vtkm::Id Distance;
1213 
1214  VTKM_CONT
1215  ScanKernel(const PortalType& portal,
1216  BinaryFunctor binary_functor,
1217  vtkm::Id stride,
1218  vtkm::Id offset)
1219  : Portal(portal)
1220  , BinaryOperator(binary_functor)
1221  , Stride(stride)
1222  , Offset(offset)
1223  , Distance(stride / 2)
1224  {
1225  }
1226 
1228  VTKM_EXEC
1229  void operator()(vtkm::Id index) const
1230  {
1231  using ValueType = typename PortalType::ValueType;
1232 
1233  vtkm::Id leftIndex = this->Offset + index * this->Stride;
1234  vtkm::Id rightIndex = leftIndex + this->Distance;
1235 
1236  if (rightIndex < this->Portal.GetNumberOfValues())
1237  {
1238  ValueType leftValue = this->Portal.Get(leftIndex);
1239  ValueType rightValue = this->Portal.Get(rightIndex);
1240  this->Portal.Set(rightIndex, BinaryOperator(leftValue, rightValue));
1241  }
1242  }
1243 };
1244 
1245 template <typename InPortalType1,
1246  typename InPortalType2,
1247  typename OutPortalType,
1248  typename BinaryFunctor>
1249 struct BinaryTransformKernel : vtkm::exec::FunctorBase
1250 {
1251  InPortalType1 InPortal1;
1252  InPortalType2 InPortal2;
1253  OutPortalType OutPortal;
1254  BinaryFunctor BinaryOperator;
1255 
1256  VTKM_CONT
1257  BinaryTransformKernel(const InPortalType1& inPortal1,
1258  const InPortalType2& inPortal2,
1259  const OutPortalType& outPortal,
1260  BinaryFunctor binaryOperator)
1261  : InPortal1(inPortal1)
1262  , InPortal2(inPortal2)
1263  , OutPortal(outPortal)
1264  , BinaryOperator(binaryOperator)
1265  {
1266  }
1267 
1269  VTKM_EXEC
1270  void operator()(vtkm::Id index) const
1271  {
1272  this->OutPortal.Set(
1273  index, this->BinaryOperator(this->InPortal1.Get(index), this->InPortal2.Get(index)));
1274  }
1275 };
1276 }
1277 }
1278 } // namespace vtkm::cont::internal
1279 
1280 #endif //vtk_m_cont_internal_FunctorsGeneral_h
VTKM_EXEC
#define VTKM_EXEC
Definition: ExportMacros.h:51
vtkm
Groups connected points that have the same field value.
Definition: Atomic.h:19
vtkm::UpperBound
VTKM_EXEC_CONT IterT UpperBound(IterT first, IterT last, const T &val, Comp comp)
Implementation of std::upper_bound that is appropriate for both control and execution environments.
Definition: UpperBound.h:30
VTKM_EXEC_CONT
#define VTKM_EXEC_CONT
Definition: ExportMacros.h:52
UnaryPredicates.h
ArrayPortalToIterators.h
vtkm::Id
vtkm::Int32 Id
Represents an ID (index into arrays).
Definition: Types.h:191
TypeTraits.h
vtkm::SortLess
Binary Predicate that takes two arguments argument x, and y and returns True if and only if x is less...
Definition: BinaryPredicates.h:45
LowerBound.h
vtkm::cont::ArrayPortalToIterators
Definition: ArrayPortalToIterators.h:27
VTKM_STATIC_ASSERT
#define VTKM_STATIC_ASSERT(condition)
Definition: StaticAssert.h:16
FunctorBase.h
vtkm::Pair::first
FirstType first
The pair's first object.
Definition: Pair.h:50
vtkm::FindFirstSetBit
VTKM_EXEC_CONT vtkm::Int32 FindFirstSetBit(vtkm::UInt32 word)
Bitwise operations.
Definition: Math.h:2791
VTKM_CONT
#define VTKM_CONT
Definition: ExportMacros.h:57
vtkm::UInt8
uint8_t UInt8
Definition: Types.h:157
BinaryOperators.h
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::UInt32
uint32_t UInt32
Definition: Types.h:161
BinaryPredicates.h
vtkm::Int32
int32_t Int32
Definition: Types.h:160
Offset
vtkm::Float32 Offset
Definition: Wireframer.h:391
vtkm::LowerBound
VTKM_EXEC_CONT IterT LowerBound(IterT first, IterT last, const T &val, Comp comp)
Implementation of std::lower_bound that is appropriate for both control and execution environments.
Definition: LowerBound.h:30
UpperBound.h
vtkm::UInt16
uint16_t UInt16
Definition: Types.h:159
vtkm::CountSetBits
VTKM_EXEC_CONT vtkm::Int32 CountSetBits(vtkm::UInt32 word)
Count the total number of bits set in word.
Definition: Math.h:2887
vtkm::Pair
A vtkm::Pair is essentially the same as an STL pair object except that the methods (constructors and ...
Definition: Pair.h:29
VTKM_SUPPRESS_EXEC_WARNINGS
#define VTKM_SUPPRESS_EXEC_WARNINGS
Definition: ExportMacros.h:53
vtkm::Pair::second
SecondType second
The pair's second object.
Definition: Pair.h:55