https://mooseframework.inl.gov
KokkosArray.h
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://www.mooseframework.org
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #pragma once
11 
12 #ifdef MOOSE_KOKKOS_SCOPE
13 #include "KokkosHeader.h"
14 #endif
15 
16 #include "Conversion.h"
17 #include "DataIO.h"
18 
19 #define usingKokkosArrayBaseMembers(T, dimension) \
20 private: \
21  using ArrayBase<T, dimension>::_n; \
22  using ArrayBase<T, dimension>::_s; \
23  using ArrayBase<T, dimension>::_d; \
24  \
25 public: \
26  using ArrayBase<T, dimension>::create; \
27  using ArrayBase<T, dimension>::createHost; \
28  using ArrayBase<T, dimension>::createDevice; \
29  using ArrayBase<T, dimension>::offset; \
30  using ArrayBase<T, dimension>::operator=
31 
32 namespace Moose
33 {
34 namespace Kokkos
35 {
36 
37 // This function simply calls ::Kokkos::kokkos_free, but it is separately defined in KokkosArray.K
38 // because the Kokkos function cannot be directly seen by the host compiler
39 void free(void * ptr);
40 
44 enum class MemcpyKind
45 {
50 };
51 
55 template <typename T, unsigned int dimension = 1>
56 class Array;
57 
65 template <typename T>
68 {
69  static const bool value = false;
70 };
71 
72 template <typename T, unsigned int dimension>
73 struct ArrayDeepCopy<Array<T, dimension>>
74 {
75  static const bool value = ArrayDeepCopy<T>::value;
76 };
78 
82 template <typename T, unsigned int dimension>
83 class ArrayBase
84 {
85 public:
89  ArrayBase() = default;
90 
95  {
96 #ifndef MOOSE_KOKKOS_SCOPE
97  static_assert(!ArrayDeepCopy<T>::value,
98  "Kokkos array cannot be deep copied outside the Kokkos compilation scope");
99 #endif
100 
101  if constexpr (ArrayDeepCopy<T>::value)
102  deepCopy(array);
103  else
104  shallowCopy(array);
105  }
106 
111 
115  void destroy();
116 
121  void shallowCopy(const ArrayBase<T, dimension> & array);
122 
127  unsigned int useCount() const { return _counter.use_count(); }
128 
129 #ifdef MOOSE_KOKKOS_SCOPE
130 
134  KOKKOS_FUNCTION bool isAlloc() const { return _is_host_alloc || _is_device_alloc; }
139  KOKKOS_FUNCTION bool isHostAlloc() const { return _is_host_alloc; }
144  KOKKOS_FUNCTION bool isDeviceAlloc() const { return _is_device_alloc; }
149  KOKKOS_FUNCTION bool isHostAlias() const { return _is_host_alias; }
154  KOKKOS_FUNCTION bool isDeviceAlias() const { return _is_device_alias; }
159  KOKKOS_FUNCTION dof_id_type size() const { return _size; }
165  KOKKOS_FUNCTION dof_id_type n(unsigned int dim) const { return _n[dim]; }
171  KOKKOS_FUNCTION T * data() const
172  {
173  KOKKOS_IF_ON_HOST(return _host_data;)
174 
175  return _device_data;
176  }
182  KOKKOS_FUNCTION T & first() const
183  {
184  KOKKOS_IF_ON_HOST(return _host_data[0];)
185 
186  return _device_data[0];
187  }
193  KOKKOS_FUNCTION T & last() const
194  {
195  KOKKOS_IF_ON_HOST(return _host_data[_size - 1];)
196 
197  return _device_data[_size - 1];
198  }
205  KOKKOS_FUNCTION T & operator[](dof_id_type i) const
206  {
207  KOKKOS_ASSERT(i < _size);
208 
209  KOKKOS_IF_ON_HOST(return _host_data[i];)
210 
211  return _device_data[i];
212  }
213 
218  T * hostData() const { return _host_data; }
223  T * deviceData() const { return _device_data; }
228  void create(const std::vector<dof_id_type> & n) { createInternal<true, true>(n); }
233  void createHost(const std::vector<dof_id_type> & n) { createInternal<true, false>(n); }
238  void createDevice(const std::vector<dof_id_type> & n) { createInternal<false, true>(n); }
243  void aliasHost(T * ptr);
248  void aliasDevice(T * ptr);
253  void offset(const std::vector<dof_id_signed_type> & d);
257  void copyToDevice();
261  void copyToHost();
269  void copyIn(const T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset = 0);
277  void copyOut(T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset = 0);
281  void copyToDeviceNested();
288  void deepCopy(const ArrayBase<T, dimension> & array);
293  void swap(ArrayBase<T, dimension> & array);
294 
299  auto & operator=(const T & scalar);
300 
304  class iterator
305  {
306  public:
307  KOKKOS_FUNCTION iterator(T * it) : it(it) {}
308  KOKKOS_FUNCTION bool operator==(const iterator & other) const { return it == other.it; }
309  KOKKOS_FUNCTION bool operator!=(const iterator & other) const { return it != other.it; }
310  KOKKOS_FUNCTION T & operator*() const { return *it; }
311  KOKKOS_FUNCTION T * operator&() const { return it; }
312  KOKKOS_FUNCTION iterator & operator++()
313  {
314  ++it;
315  return *this;
316  }
317  KOKKOS_FUNCTION iterator operator++(int)
318  {
319  iterator pre = *this;
320  ++it;
321  return pre;
322  }
323 
324  private:
325  T * it;
326  };
327 
332  KOKKOS_FUNCTION iterator begin() const
333  {
334  KOKKOS_IF_ON_HOST(return iterator(_host_data);)
335 
336  return iterator(_device_data);
337  }
342  KOKKOS_FUNCTION iterator end() const
343  {
344  KOKKOS_IF_ON_HOST(return iterator(_host_data + _size);)
345 
346  return iterator(_device_data + _size);
347  }
348 #endif
349 
350 protected:
354  dof_id_type _n[dimension] = {0};
358  dof_id_type _s[dimension] = {0};
362  dof_id_signed_type _d[dimension] = {0};
363 
364 #ifdef MOOSE_KOKKOS_SCOPE
365 
371  template <bool host, bool device>
372  void createInternal(const std::vector<dof_id_type> & n);
379  void createInternal(const std::vector<dof_id_type> & n, bool host, bool device);
388  template <typename TargetSpace, typename SourceSpace>
389  void copyInternal(T * target, const T * source, dof_id_type n);
390 #endif
391 
392 private:
393 #ifdef MOOSE_KOKKOS_SCOPE
394 
397  void allocHost();
401  void allocDevice();
402 #endif
403 
407  std::shared_ptr<unsigned int> _counter;
411  bool _is_init = false;
415  bool _is_host_alloc = false;
419  bool _is_device_alloc = false;
423  bool _is_host_alias = false;
427  bool _is_device_alias = false;
431  T * _host_data = nullptr;
435  T * _device_data = nullptr;
440 };
441 
442 template <typename T, unsigned int dimension>
443 void
445 {
446  if (!_counter)
447  return;
448 
449  if (_counter.use_count() > 1)
450  {
451  _host_data = nullptr;
452  _device_data = nullptr;
453  }
454  else if (_counter.use_count() == 1)
455  {
456  if (_is_host_alloc && !_is_host_alias)
457  {
458  if constexpr (std::is_default_constructible<T>::value)
459  // Allocated by new
460  delete[] _host_data;
461  else
462  {
463  // Allocated by malloc
464  for (dof_id_type i = 0; i < _size; ++i)
465  _host_data[i].~T();
466 
467  std::free(_host_data);
468  }
469  }
470 
471  if (_is_device_alloc && !_is_device_alias)
472  Moose::Kokkos::free(_device_data);
473  }
474 
475  _size = 0;
476 
477  for (unsigned int i = 0; i < dimension; ++i)
478  {
479  _n[i] = 0;
480  _s[i] = 0;
481  _d[i] = 0;
482  }
483 
484  _is_init = false;
485  _is_host_alloc = false;
486  _is_device_alloc = false;
487  _is_host_alias = false;
488  _is_device_alias = false;
489 
490  _counter.reset();
491 }
492 
493 template <typename T, unsigned int dimension>
494 void
496 {
497  destroy();
498 
499  _counter = array._counter;
500 
501  _size = array._size;
502 
503  for (unsigned int i = 0; i < dimension; ++i)
504  {
505  _n[i] = array._n[i];
506  _s[i] = array._s[i];
507  _d[i] = array._d[i];
508  }
509 
510  _is_init = array._is_init;
511  _is_host_alloc = array._is_host_alloc;
512  _is_device_alloc = array._is_device_alloc;
513  _is_host_alias = array._is_host_alias;
514  _is_device_alias = array._is_device_alias;
515 
516  _host_data = array._host_data;
517  _device_data = array._device_data;
518 }
519 
520 #ifdef MOOSE_KOKKOS_SCOPE
521 template <typename T, unsigned int dimension>
522 void
524 {
525  if (!_is_init)
526  mooseError("Kokkos array error: attempted to alias host data before array initialization.");
527 
528  if (_is_host_alloc && !_is_host_alias)
529  mooseError("Kokkos array error: cannot alias host data because host data was not aliased.");
530 
531  _host_data = ptr;
532  _is_host_alloc = true;
533  _is_host_alias = true;
534 }
535 
536 template <typename T, unsigned int dimension>
537 void
539 {
540  if (!_is_init)
541  mooseError("Kokkos array error: attempted to alias device data before array initialization.");
542 
543  if (_is_device_alloc && !_is_device_alias)
544  mooseError("Kokkos array error: cannot alias device data because device data was not aliased.");
545 
546  _device_data = ptr;
547  _is_device_alloc = true;
548  _is_device_alias = true;
549 }
550 
551 template <typename T, unsigned int dimension>
552 void
554 {
555  if (_is_host_alloc)
556  return;
557 
558  if constexpr (std::is_default_constructible<T>::value)
559  _host_data = new T[_size];
560  else
561  _host_data = static_cast<T *>(std::malloc(_size * sizeof(T)));
562 
563  _is_host_alloc = true;
564 }
565 
566 template <typename T, unsigned int dimension>
567 void
569 {
570  if (_is_device_alloc)
571  return;
572 
573  _device_data =
574  static_cast<T *>(::Kokkos::kokkos_malloc<ExecSpace::memory_space>(_size * sizeof(T)));
575 
576  _is_device_alloc = true;
577 }
578 
579 template <typename T, unsigned int dimension>
580 template <bool host, bool device>
581 void
582 ArrayBase<T, dimension>::createInternal(const std::vector<dof_id_type> & n)
583 {
584  if (n.size() != dimension)
585  mooseError("Kokkos array error: the number of dimensions provided (",
586  n.size(),
587  ") must match the array dimension (",
588  dimension,
589  ").");
590 
591  if (_counter)
592  destroy();
593 
594  _counter = std::make_shared<unsigned int>();
595 
596  _size = 1;
597  _s[0] = 1;
598 
599  for (const auto i : make_range(dimension))
600  {
601  _n[i] = n[i];
602  _size *= n[i];
603 
604  if (i)
605  _s[i] = _s[i - 1] * _n[i - 1];
606  }
607 
608  if constexpr (host)
609  allocHost();
610 
611  if constexpr (device)
612  allocDevice();
613 
614  _is_init = true;
615 }
616 
617 template <typename T, unsigned int dimension>
618 void
619 ArrayBase<T, dimension>::createInternal(const std::vector<dof_id_type> & n, bool host, bool device)
620 {
621  if (host && device)
622  createInternal<true, true>(n);
623  else if (host && !device)
624  createInternal<true, false>(n);
625  else if (!host && device)
626  createInternal<false, true>(n);
627  else
628  createInternal<false, false>(n);
629 }
630 
631 template <typename T, unsigned int dimension>
632 template <typename TargetSpace, typename SourceSpace>
633 void
634 ArrayBase<T, dimension>::copyInternal(T * target, const T * source, dof_id_type n)
635 {
636  ::Kokkos::Impl::DeepCopy<TargetSpace, SourceSpace>(target, source, n * sizeof(T));
637  ::Kokkos::fence();
638 }
639 
640 template <typename T, unsigned int dimension>
641 void
642 ArrayBase<T, dimension>::offset(const std::vector<dof_id_signed_type> & d)
643 {
644  if (d.size() > dimension)
645  mooseError("Kokkos array error: the number of offsets provided (",
646  d.size(),
647  ") cannot be larger than the array dimension (",
648  dimension,
649  ").");
650 
651  for (const auto i : index_range(d))
652  _d[i] = d[i];
653 }
654 
655 template <typename T, unsigned int dimension>
656 void
658 {
659  // If host side memory is not allocated, do nothing
660  if (!_is_host_alloc)
661  return;
662 
663  // If device side memory is not allocated,
664  if (!_is_device_alloc)
665  {
666  if (_counter.use_count() == 1)
667  // allocate memory if this array is not shared with other arrays
668  allocDevice();
669  else
670  // print error if this array is shared with other arrays
671  mooseError("Kokkos array error: cannot copy from host to device because device side memory "
672  "was not allocated and array is being shared with other arrays.");
673  }
674 
675  // Copy from host to device
676  copyInternal<MemSpace, ::Kokkos::HostSpace>(_device_data, _host_data, _size);
677 }
678 
679 template <typename T, unsigned int dimension>
680 void
682 {
683  // If device side memory is not allocated, do nothing
684  if (!_is_device_alloc)
685  return;
686 
687  // If host side memory is not allocated,
688  if (!_is_host_alloc)
689  {
690  if (_counter.use_count() == 1)
691  // allocate memory if this array is not shared with other arrays
692  allocHost();
693  else
694  // print error if this array is shared with other arrays
695  mooseError("Kokkos array error: cannot copy from device to host because host side memory "
696  "was not allocated and array is being shared with other arrays.");
697  }
698 
699  // Copy from device to host
700  copyInternal<::Kokkos::HostSpace, MemSpace>(_host_data, _device_data, _size);
701 }
702 
703 template <typename T, unsigned int dimension>
704 void
706 {
707  if (n > _size)
708  mooseError("Kokkos array error: cannot copyin data larger than the array size.");
709 
710  if (offset > _size)
711  mooseError("Kokkos array error: offset cannot be larger than the array size.");
712 
713  if (dir == MemcpyKind::HOST_TO_HOST)
714  {
715  // If host side memory is not allocated, do nothing
716  if (!_is_host_alloc)
717  return;
718 
719  // Copy from host to host
720  copyInternal<::Kokkos::HostSpace, ::Kokkos::HostSpace>(_host_data + offset, ptr, n);
721  }
722  else if (dir == MemcpyKind::HOST_TO_DEVICE)
723  {
724  // If device side memory is not allocated, do nothing
725  if (!_is_device_alloc)
726  return;
727 
728  // Copy from host to device
729  copyInternal<MemSpace, ::Kokkos::HostSpace>(_device_data + offset, ptr, n);
730  }
731  else if (dir == MemcpyKind::DEVICE_TO_HOST)
732  {
733  // If host side memory is not allocated, do nothing
734  if (!_is_host_alloc)
735  return;
736 
737  // Copy from device to host
738  copyInternal<::Kokkos::HostSpace, MemSpace>(_host_data + offset, ptr, n);
739  }
740  else if (dir == MemcpyKind::DEVICE_TO_DEVICE)
741  {
742  // If device side memory is not allocated, do nothing
743  if (!_is_device_alloc)
744  return;
745 
746  // Copy from device to device
747  copyInternal<MemSpace, MemSpace>(_device_data + offset, ptr, n);
748  }
749 }
750 
751 template <typename T, unsigned int dimension>
752 void
754 {
755  if (n > _size)
756  mooseError("Kokkos array error: cannot copyout data larger than the array size.");
757 
758  if (offset > _size)
759  mooseError("Kokkos array error: offset cannot be larger than the array size.");
760 
761  if (dir == MemcpyKind::HOST_TO_HOST)
762  {
763  // If host side memory is not allocated, do nothing
764  if (!_is_host_alloc)
765  return;
766 
767  // Copy from host to host
768  copyInternal<::Kokkos::HostSpace, ::Kokkos::HostSpace>(ptr, _host_data + offset, n);
769  }
770  else if (dir == MemcpyKind::HOST_TO_DEVICE)
771  {
772  // If host side memory is not allocated, do nothing
773  if (!_is_host_alloc)
774  return;
775 
776  // Copy from host to device
777  copyInternal<MemSpace, ::Kokkos::HostSpace>(ptr, _host_data + offset, n);
778  }
779  else if (dir == MemcpyKind::DEVICE_TO_HOST)
780  {
781  // If device side memory is not allocated, do nothing
782  if (!_is_device_alloc)
783  return;
784 
785  // Copy from device to host
786  copyInternal<::Kokkos::HostSpace, MemSpace>(ptr, _device_data + offset, n);
787  }
788  else if (dir == MemcpyKind::DEVICE_TO_DEVICE)
789  {
790  // If device side memory is not allocated, do nothing
791  if (!_is_device_alloc)
792  return;
793 
794  // Copy from device to device
795  copyInternal<MemSpace, MemSpace>(ptr, _device_data + offset, n);
796  }
797 }
798 
799 template <typename T>
800 void
801 copyToDeviceInner(T & /* data */)
802 {
803 }
804 
805 template <typename T, unsigned int dimension>
806 void
808 {
809  data.copyToDeviceNested();
810 }
811 
812 template <typename T, unsigned int dimension>
813 void
815 {
816  for (unsigned int i = 0; i < _size; ++i)
817  copyToDeviceInner(_host_data[i]);
818 
819  copyToDevice();
820 }
821 
822 template <typename T, unsigned int dimension>
823 void
825 {
827  mooseError(
828  "Kokkos array error: cannot deep copy using constructor from array without host data.");
829 
830  std::vector<dof_id_type> n(std::begin(array._n), std::end(array._n));
831 
832  createInternal(n, array._is_host_alloc, array._is_device_alloc);
833 
834  if constexpr (ArrayDeepCopy<T>::value)
835  {
836  for (dof_id_type i = 0; i < _size; ++i)
837  new (_host_data + i) T(array._host_data[i]);
838 
839  copyToDevice();
840  }
841  else
842  {
843  if (_is_host_alloc)
844  std::memcpy(_host_data, array._host_data, _size * sizeof(T));
845 
846  if (_is_device_alloc)
847  copyInternal<MemSpace, MemSpace>(_device_data, array._device_data, _size);
848  }
849 
850  for (unsigned int i = 0; i < dimension; ++i)
851  {
852  _d[i] = array._d[i];
853  _s[i] = array._s[i];
854  }
855 }
856 
857 template <typename T, unsigned int dimension>
858 void
860 {
862 
863  clone.shallowCopy(*this);
864  this->shallowCopy(array);
865  array.shallowCopy(clone);
866 }
867 
868 template <typename T, unsigned int dimension>
869 auto &
871 {
872  if (_is_host_alloc)
873  std::fill_n(_host_data, _size, scalar);
874 
875  if (_is_device_alloc)
876  {
877  ::Kokkos::View<T *, MemSpace, ::Kokkos::MemoryTraits<::Kokkos::Unmanaged>> data(_device_data,
878  _size);
879  ::Kokkos::Experimental::fill_n(ExecSpace(), data, _size, scalar);
880  }
881 
882  return *this;
883 }
884 
885 template <typename T, unsigned int dimension>
886 void
887 dataStore(std::ostream & stream, Array<T, dimension> & array, void * context)
888 {
890 
891  bool is_alloc = array.isAlloc();
892  dataStore(stream, is_alloc, nullptr);
893 
894  if (!is_alloc)
895  return;
896 
897  std::string type = typeid(T).name();
898  dataStore(stream, type, nullptr);
899 
900  unsigned int dim = dimension;
901  dataStore(stream, dim, nullptr);
902 
903  for (unsigned int dim = 0; dim < dimension; ++dim)
904  {
905  auto n = array.n(dim);
906  dataStore(stream, n, nullptr);
907  }
908 
909  if (array.isDeviceAlloc())
910  {
911  // We use malloc/free because we just want a memory copy
912  // If T is a Kokkos array and we use new/delete or vector to copy it out,
913  // the arrays will be destroyed on cleanup
914 
915  T * data = static_cast<T *>(std::malloc(array.size() * sizeof(T)));
916 
917  array.copyOut(data, MemcpyKind::DEVICE_TO_HOST, array.size());
918 
919  for (dof_id_type i = 0; i < array.size(); ++i)
920  dataStore(stream, data[i], context);
921 
922  std::free(data);
923  }
924  else
925  for (auto & value : array)
926  dataStore(stream, value, context);
927 }
928 
929 template <typename T, unsigned int dimension>
930 void
931 dataLoad(std::istream & stream, Array<T, dimension> & array, void * context)
932 {
934 
935  bool is_alloc;
936  dataLoad(stream, is_alloc, nullptr);
937 
938  if (!is_alloc)
939  return;
940 
941  std::string from_type_name;
942  dataLoad(stream, from_type_name, nullptr);
943 
944  if (from_type_name != typeid(T).name())
945  mooseError("Kokkos array error: cannot load an array because the stored array is of type '",
946  MooseUtils::prettyCppType(libMesh::demangle(from_type_name.c_str())),
947  "' but the loading array is of type '",
949  "'.");
950 
951  unsigned int from_dimension;
952  dataLoad(stream, from_dimension, nullptr);
953 
954  if (from_dimension != dimension)
955  mooseError("Kokkos array error: cannot load an array because the stored array is ",
956  from_dimension,
957  "D but the loading array is ",
958  dimension,
959  "D.");
960 
961  std::vector<dof_id_type> from_n(dimension);
962  std::vector<dof_id_type> n(dimension);
963 
964  for (unsigned int dim = 0; dim < dimension; ++dim)
965  {
966  dataLoad(stream, from_n[dim], nullptr);
967  n[dim] = array.n(dim);
968  }
969 
970  if (from_n != n)
971  mooseError("Kokkos array error: cannot load an array because the stored array has dimensions (",
972  Moose::stringify(from_n),
973  ") but the loading array has dimensions (",
974  Moose::stringify(n),
975  ").");
976 
977  if (array.isHostAlloc())
978  {
979  for (auto & value : array)
980  dataLoad(stream, value, context);
981 
982  if (array.isDeviceAlloc())
983  array.copyToDevice();
984  }
985  else
986  {
987  std::vector<T> data(array.size());
988 
989  for (auto & value : data)
990  dataLoad(stream, value, context);
991 
992  array.copyIn(data.data(), MemcpyKind::HOST_TO_DEVICE, array.size());
993  }
994 }
995 #endif
996 
1008 template <typename T>
1010 class Array<T, 1> : public ArrayBase<T, 1>
1011 {
1012 #ifdef MOOSE_KOKKOS_SCOPE
1013  usingKokkosArrayBaseMembers(T, 1);
1014 #endif
1015 
1016 public:
1020  Array() = default;
1024  Array(const Array<T, 1> & array) : ArrayBase<T, 1>(array) {}
1029  auto & operator=(const Array<T, 1> & array)
1030  {
1031  this->shallowCopy(array);
1032 
1033  return *this;
1034  }
1035 
1036 #ifdef MOOSE_KOKKOS_SCOPE
1037 
1043  Array(dof_id_type n0) { create(n0); }
1050  Array(const std::vector<T> & vector) { *this = vector; }
1051 
1056  void init(dof_id_type n0) { this->template createInternal<false, false>({n0}); }
1061  void create(dof_id_type n0) { this->template createInternal<true, true>({n0}); }
1066  void createHost(dof_id_type n0) { this->template createInternal<true, false>({n0}); }
1071  void createDevice(dof_id_type n0) { this->template createInternal<false, true>({n0}); }
1077 
1085  template <bool host, bool device>
1086  void copyVector(const std::vector<T> & vector)
1087  {
1088  this->template createInternal<host, device>({static_cast<dof_id_type>(vector.size())});
1089 
1090  if (host)
1091  std::memcpy(this->hostData(), vector.data(), this->size() * sizeof(T));
1092 
1093  if (device)
1094  this->template copyInternal<MemSpace, ::Kokkos::HostSpace>(
1095  this->deviceData(), vector.data(), this->size());
1096  }
1104  template <bool host, bool device>
1105  void copySet(const std::set<T> & set)
1106  {
1107  std::vector<T> vector(set.begin(), set.end());
1108 
1109  copyVector<host, device>(vector);
1110  }
1111 
1117  auto & operator=(const std::vector<T> & vector)
1118  {
1119  copyVector<true, true>(vector);
1120 
1121  return *this;
1122  }
1128  auto & operator=(const std::set<T> & set)
1129  {
1130  copySet<true, true>(set);
1131 
1132  return *this;
1133  }
1134 
1141  KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0) const
1142  {
1143  KOKKOS_ASSERT(i0 - _d[0] >= 0 && static_cast<dof_id_type>(i0 - _d[0]) < _n[0]);
1144 
1145  return this->operator[](i0 - _d[0]);
1146  }
1147 #endif
1148 };
1149 
1150 template <typename T>
1152 {
1153 #ifdef MOOSE_KOKKOS_SCOPE
1154  usingKokkosArrayBaseMembers(T, 2);
1155 #endif
1156 
1157 public:
1161  Array() = default;
1165  Array(const Array<T, 2> & array) : ArrayBase<T, 2>(array) {}
1170  auto & operator=(const Array<T, 2> & array)
1171  {
1172  this->shallowCopy(array);
1173 
1174  return *this;
1175  }
1176 
1177 #ifdef MOOSE_KOKKOS_SCOPE
1178 
1185  Array(dof_id_type n0, dof_id_type n1) { create(n0, n1); }
1186 
1193  {
1194  this->template createInternal<false, false>({n0, n1});
1195  }
1202  {
1203  this->template createInternal<true, true>({n0, n1});
1204  }
1211  {
1212  this->template createInternal<true, false>({n0, n1});
1213  }
1220  {
1221  this->template createInternal<false, true>({n0, n1});
1222  }
1229 
1237  KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0, dof_id_signed_type i1) const
1238  {
1239  KOKKOS_ASSERT(i0 - _d[0] >= 0 && static_cast<dof_id_type>(i0 - _d[0]) < _n[0]);
1240  KOKKOS_ASSERT(i1 - _d[1] >= 0 && static_cast<dof_id_type>(i1 - _d[1]) < _n[1]);
1241 
1242  return this->operator[](i0 - _d[0] + (i1 - _d[1]) * _s[1]);
1243  }
1244 #endif
1245 };
1246 
1247 template <typename T>
1249 {
1250 #ifdef MOOSE_KOKKOS_SCOPE
1251  usingKokkosArrayBaseMembers(T, 3);
1252 #endif
1253 
1254 public:
1258  Array() = default;
1262  Array(const Array<T, 3> & array) : ArrayBase<T, 3>(array) {}
1267  auto & operator=(const Array<T, 3> & array)
1268  {
1269  this->shallowCopy(array);
1270 
1271  return *this;
1272  }
1273 
1274 #ifdef MOOSE_KOKKOS_SCOPE
1275 
1283  Array(dof_id_type n0, dof_id_type n1, dof_id_type n2) { create(n0, n1, n2); }
1284 
1292  {
1293  this->template createInternal<false, false>({n0, n1, n2});
1294  }
1302  {
1303  this->template createInternal<true, true>({n0, n1, n2});
1304  }
1312  {
1313  this->template createInternal<true, false>({n0, n1, n2});
1314  }
1322  {
1323  this->template createInternal<false, true>({n0, n1, n2});
1324  }
1332  {
1333  ArrayBase<T, 3>::offset({d0, d1, d2});
1334  }
1335 
1344  KOKKOS_FUNCTION T &
1346  {
1347  KOKKOS_ASSERT(i0 - _d[0] >= 0 && static_cast<dof_id_type>(i0 - _d[0]) < _n[0]);
1348  KOKKOS_ASSERT(i1 - _d[1] >= 0 && static_cast<dof_id_type>(i1 - _d[1]) < _n[1]);
1349  KOKKOS_ASSERT(i2 - _d[2] >= 0 && static_cast<dof_id_type>(i2 - _d[2]) < _n[2]);
1350 
1351  return this->operator[](i0 - _d[0] + (i1 - _d[1]) * _s[1] + (i2 - _d[2]) * _s[2]);
1352  }
1353 #endif
1354 };
1355 
1356 template <typename T>
1358 {
1359 #ifdef MOOSE_KOKKOS_SCOPE
1360  usingKokkosArrayBaseMembers(T, 4);
1361 #endif
1362 
1363 public:
1367  Array() = default;
1371  Array(const Array<T, 4> & array) : ArrayBase<T, 4>(array) {}
1376  auto & operator=(const Array<T, 4> & array)
1377  {
1378  this->shallowCopy(array);
1379 
1380  return *this;
1381  }
1382 
1383 #ifdef MOOSE_KOKKOS_SCOPE
1384 
1393  Array(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3) { create(n0, n1, n2, n3); }
1394 
1403  {
1404  this->template createInternal<false, false>({n0, n1, n2, n3});
1405  }
1414  {
1415  this->template createInternal<true, true>({n0, n1, n2, n3});
1416  }
1425  {
1426  this->template createInternal<true, false>({n0, n1, n2, n3});
1427  }
1436  {
1437  this->template createInternal<false, true>({n0, n1, n2, n3});
1438  }
1446  void
1448  {
1449  ArrayBase<T, 4>::offset({d0, d1, d2, d3});
1450  }
1451 
1461  KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0,
1462  dof_id_signed_type i1,
1463  dof_id_signed_type i2,
1464  dof_id_signed_type i3) const
1465  {
1466  KOKKOS_ASSERT(i0 - _d[0] >= 0 && static_cast<dof_id_type>(i0 - _d[0]) < _n[0]);
1467  KOKKOS_ASSERT(i1 - _d[1] >= 0 && static_cast<dof_id_type>(i1 - _d[1]) < _n[1]);
1468  KOKKOS_ASSERT(i2 - _d[2] >= 0 && static_cast<dof_id_type>(i2 - _d[2]) < _n[2]);
1469  KOKKOS_ASSERT(i3 - _d[3] >= 0 && static_cast<dof_id_type>(i3 - _d[3]) < _n[3]);
1470 
1471  return this->operator[](i0 - _d[0] + (i1 - _d[1]) * _s[1] + (i2 - _d[2]) * _s[2] +
1472  (i3 - _d[3]) * _s[3]);
1473  }
1474 #endif
1475 };
1476 
1477 template <typename T>
1479 {
1480 #ifdef MOOSE_KOKKOS_SCOPE
1481  usingKokkosArrayBaseMembers(T, 5);
1482 #endif
1483 
1484 public:
1488  Array() = default;
1492  Array(const Array<T, 5> & array) : ArrayBase<T, 5>(array) {}
1497  auto & operator=(const Array<T, 5> & array)
1498  {
1499  this->shallowCopy(array);
1500 
1501  return *this;
1502  }
1503 
1504 #ifdef MOOSE_KOKKOS_SCOPE
1505 
1516  {
1517  create(n0, n1, n2, n3, n4);
1518  }
1519 
1529  {
1530  this->template createInternal<false, false>({n0, n1, n2, n3, n4});
1531  }
1541  {
1542  this->template createInternal<true, true>({n0, n1, n2, n3, n4});
1543  }
1553  {
1554  this->template createInternal<true, false>({n0, n1, n2, n3, n4});
1555  }
1565  {
1566  this->template createInternal<false, true>({n0, n1, n2, n3, n4});
1567  }
1577  dof_id_signed_type d1,
1578  dof_id_signed_type d2,
1579  dof_id_signed_type d3,
1580  dof_id_signed_type d4)
1581  {
1582  ArrayBase<T, 5>::offset({d0, d1, d2, d3, d4});
1583  }
1584 
1595  KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0,
1596  dof_id_signed_type i1,
1597  dof_id_signed_type i2,
1598  dof_id_signed_type i3,
1599  dof_id_signed_type i4) const
1600  {
1601  KOKKOS_ASSERT(i0 - _d[0] >= 0 && static_cast<dof_id_type>(i0 - _d[0]) < _n[0]);
1602  KOKKOS_ASSERT(i1 - _d[1] >= 0 && static_cast<dof_id_type>(i1 - _d[1]) < _n[1]);
1603  KOKKOS_ASSERT(i2 - _d[2] >= 0 && static_cast<dof_id_type>(i2 - _d[2]) < _n[2]);
1604  KOKKOS_ASSERT(i3 - _d[3] >= 0 && static_cast<dof_id_type>(i3 - _d[3]) < _n[3]);
1605  KOKKOS_ASSERT(i4 - _d[4] >= 0 && static_cast<dof_id_type>(i4 - _d[4]) < _n[4]);
1606 
1607  return this->operator[](i0 - _d[0] + (i1 - _d[1]) * _s[1] + (i2 - _d[2]) * _s[2] +
1608  (i3 - _d[3]) * _s[3] + (i4 - _d[4]) * _s[4]);
1609  }
1610 #endif
1611 };
1613 
1614 template <typename T>
1616 template <typename T>
1618 template <typename T>
1620 template <typename T>
1622 template <typename T>
1624 
1625 } // namespace Kokkos
1626 } // namespace Moose
std::string name(const ElemQuality q)
The specialization of the Kokkos array class for each dimension.
Definition: KokkosArray.h:1010
void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
Initialize and allocate array with given dimensions on device only.
Definition: KokkosArray.h:1564
void swap(ArrayBase< T, dimension > &array)
Swap with another Kokkos array.
Definition: KokkosArray.h:859
The Kokkos array class.
Definition: KokkosArray.h:56
KOKKOS_FUNCTION dof_id_type n(unsigned int dim) const
Get the size of a dimension.
Definition: KokkosArray.h:165
KOKKOS_FUNCTION bool operator==(const iterator &other) const
Definition: KokkosArray.h:308
void createHost(dof_id_type n0, dof_id_type n1)
Initialize and allocate array with given dimensions on host only.
Definition: KokkosArray.h:1210
bool _is_device_alias
Flag whether the device data points to an external data.
Definition: KokkosArray.h:427
void copyOut(T *ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset=0)
Copy data to an external data from this array.
Definition: KokkosArray.h:753
KOKKOS_FUNCTION T * operator &() const
Definition: KokkosArray.h:311
bool _is_device_alloc
Flag whether device data was allocated.
Definition: KokkosArray.h:419
dof_id_type _n[dimension]
Size of each dimension.
Definition: KokkosArray.h:354
void shallowCopy(const ArrayBase< T, dimension > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:495
KOKKOS_FUNCTION T & first() const
Get the first element.
Definition: KokkosArray.h:182
void copyToHost()
Copy data from device to host.
Definition: KokkosArray.h:681
T * hostData() const
Get the host data pointer.
Definition: KokkosArray.h:218
KOKKOS_FUNCTION dof_id_type size() const
Get the total array size.
Definition: KokkosArray.h:159
Array(dof_id_type n0, dof_id_type n1)
Constructor Initialize and allocate array with given dimensions This allocates both host and device d...
Definition: KokkosArray.h:1185
Array(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
Constructor Initialize and allocate array with given dimensions This allocates both host and device d...
Definition: KokkosArray.h:1515
void init(dof_id_type n0, dof_id_type n1)
Initialize array with given dimensions but do not allocate.
Definition: KokkosArray.h:1192
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
Definition: MooseError.h:323
void offset(const std::vector< dof_id_signed_type > &d)
Apply starting index offsets to each dimension.
Definition: KokkosArray.h:642
void destroy()
Free all data and reset.
Definition: KokkosArray.h:444
KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0) const
Get an array entry.
Definition: KokkosArray.h:1141
ArrayBase(const ArrayBase< T, dimension > &array)
Copy constructor.
Definition: KokkosArray.h:94
void allocHost()
Allocate host data for an initialized array that has not allocated host data.
Definition: KokkosArray.h:553
Array(dof_id_type n0, dof_id_type n1, dof_id_type n2)
Constructor Initialize and allocate array with given dimensions This allocates both host and device d...
Definition: KokkosArray.h:1283
Array(const Array< T, 1 > &array)
Copy constructor.
Definition: KokkosArray.h:1024
KOKKOS_FUNCTION iterator end() const
Get the end iterator.
Definition: KokkosArray.h:342
KOKKOS_FUNCTION T & last() const
Get the last element.
Definition: KokkosArray.h:193
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition: Moose.h:159
MemcpyKind
The enumerator that dictates the memory copy direction.
Definition: KokkosArray.h:44
auto & operator=(const Array< T, 4 > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:1376
void create(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
Initialize and allocate array with given dimensions on host and device.
Definition: KokkosArray.h:1413
void copyToDevice()
Copy data from host to device.
Definition: KokkosArray.h:657
KOKKOS_FUNCTION bool isDeviceAlloc() const
Get whether the array was allocated on device.
Definition: KokkosArray.h:144
Array(const std::vector< T > &vector)
Constructor Initialize and allocate array by copying a standard vector variable This allocates and co...
Definition: KokkosArray.h:1050
KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0, dof_id_signed_type i1) const
Get an array entry.
Definition: KokkosArray.h:1237
Array(const Array< T, 5 > &array)
Copy constructor.
Definition: KokkosArray.h:1492
KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0, dof_id_signed_type i1, dof_id_signed_type i2, dof_id_signed_type i3) const
Get an array entry.
Definition: KokkosArray.h:1461
~ArrayBase()
Destructor.
Definition: KokkosArray.h:110
void offset(dof_id_signed_type d0, dof_id_signed_type d1, dof_id_signed_type d2, dof_id_signed_type d3)
Set starting index offsets.
Definition: KokkosArray.h:1447
void copySet(const std::set< T > &set)
Copy a standard set variable This re-initializes and re-allocates array with the size of the set...
Definition: KokkosArray.h:1105
Array(const Array< T, 4 > &array)
Copy constructor.
Definition: KokkosArray.h:1371
void create(dof_id_type n0, dof_id_type n1, dof_id_type n2)
Initialize and allocate array with given dimensions on host and device.
Definition: KokkosArray.h:1301
void offset(dof_id_signed_type d0, dof_id_signed_type d1)
Set starting index offsets.
Definition: KokkosArray.h:1228
Array(const Array< T, 3 > &array)
Copy constructor.
Definition: KokkosArray.h:1262
void create(dof_id_type n0, dof_id_type n1)
Initialize and allocate array with given dimensions on host and device.
Definition: KokkosArray.h:1201
void createDevice(dof_id_type n0)
Initialize and allocate array with given dimensions on device only.
Definition: KokkosArray.h:1071
ArrayBase()=default
Default constructor.
void aliasDevice(T *ptr)
Point the device data to an external data instead of allocating it.
Definition: KokkosArray.h:538
void createDevice(dof_id_type n0, dof_id_type n1)
Initialize and allocate array with given dimensions on device only.
Definition: KokkosArray.h:1219
void copyIn(const T *ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset=0)
Copy data from an external data to this array.
Definition: KokkosArray.h:705
bool _is_init
Flag whether array was initialized.
Definition: KokkosArray.h:411
void createHost(dof_id_type n0)
Initialize and allocate array with given dimensions on host only.
Definition: KokkosArray.h:1066
KOKKOS_FUNCTION iterator operator++(int)
Definition: KokkosArray.h:317
dof_id_type _size
Total size.
Definition: KokkosArray.h:439
KOKKOS_FUNCTION bool operator!=(const iterator &other) const
Definition: KokkosArray.h:309
auto & operator=(const std::vector< T > &vector)
Copy a standard vector variable This allocates and copies to both host and device data...
Definition: KokkosArray.h:1117
KOKKOS_FUNCTION T & operator[](dof_id_type i) const
Get an array entry.
Definition: KokkosArray.h:205
static const bool value
Definition: KokkosArray.h:69
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
void init(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
Initialize array with given dimensions but do not allocate.
Definition: KokkosArray.h:1528
void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2)
Initialize and allocate array with given dimensions on host only.
Definition: KokkosArray.h:1311
dof_id_type _s[dimension]
Stride of each dimension.
Definition: KokkosArray.h:358
KOKKOS_FUNCTION bool isDeviceAlias() const
Get whether the device array was aliased.
Definition: KokkosArray.h:154
auto & operator=(const Array< T, 3 > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:1267
void copyToDeviceInner(T &)
Definition: KokkosArray.h:801
KOKKOS_FUNCTION bool isHostAlloc() const
Get whether the array was allocated on host.
Definition: KokkosArray.h:139
void deepCopy(const ArrayBase< T, dimension > &array)
Deep copy another Kokkos array If ArrayDeepCopy<T>::value is true, it will copy-construct each entry ...
Definition: KokkosArray.h:824
KOKKOS_FUNCTION bool isAlloc() const
Get whether the array was allocated either on host or device.
Definition: KokkosArray.h:134
void createDevice(const std::vector< dof_id_type > &n)
Allocate array on device only.
Definition: KokkosArray.h:238
int8_t dof_id_signed_type
void init(dof_id_type n0)
Initialize array with given dimensions but do not allocate.
Definition: KokkosArray.h:1056
The base class for Kokkos arrays.
Definition: KokkosArray.h:83
void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
Initialize and allocate array with given dimensions on host only.
Definition: KokkosArray.h:1552
void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
Initialize and allocate array with given dimensions on host only.
Definition: KokkosArray.h:1424
unsigned int useCount() const
Get the reference count.
Definition: KokkosArray.h:127
void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
Initialize and allocate array with given dimensions on device only.
Definition: KokkosArray.h:1435
std::string stringify(const T &t)
conversion to string
Definition: Conversion.h:64
std::string demangle(const char *name)
void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2)
Initialize and allocate array with given dimensions on device only.
Definition: KokkosArray.h:1321
KOKKOS_FUNCTION T * data() const
Get the data pointer.
Definition: KokkosArray.h:171
void copyInternal(T *target, const T *source, dof_id_type n)
The internal method to perform a memory copy.
Definition: KokkosArray.h:634
void copyToDeviceNested()
Copy all the nested Kokkos arrays including self from host to device.
Definition: KokkosArray.h:814
T * _host_data
Host data.
Definition: KokkosArray.h:431
void free(void *ptr)
void create(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
Initialize and allocate array with given dimensions on host and device.
Definition: KokkosArray.h:1540
auto & operator=(const Array< T, 5 > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:1497
The type trait that determines the default behavior of copy constructor and deepCopy() If this type t...
Definition: KokkosArray.h:67
KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0, dof_id_signed_type i1, dof_id_signed_type i2) const
Get an array entry.
Definition: KokkosArray.h:1345
bool _is_host_alias
Flag whether the host data points to an external data.
Definition: KokkosArray.h:423
KOKKOS_FUNCTION iterator begin() const
Get the beginning iterator.
Definition: KokkosArray.h:332
void create(dof_id_type n0)
Initialize and allocate array with given dimensions on host and device.
Definition: KokkosArray.h:1061
T * deviceData() const
Get the device data pointer.
Definition: KokkosArray.h:223
void dataStore(std::ostream &stream, Array< T, dimension > &array, void *context)
Definition: KokkosArray.h:887
void dataLoad(std::istream &stream, Array< T, dimension > &array, void *context)
Definition: KokkosArray.h:931
std::shared_ptr< unsigned int > _counter
Reference counter.
Definition: KokkosArray.h:407
auto & operator=(const T &scalar)
Assign a scalar value uniformly.
Definition: KokkosArray.h:870
T * _device_data
Device data.
Definition: KokkosArray.h:435
void createInternal(const std::vector< dof_id_type > &n)
The internal method to initialize and allocate this array.
Definition: KokkosArray.h:582
void init(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
Initialize array with given dimensions but do not allocate.
Definition: KokkosArray.h:1402
void offset(dof_id_signed_type d0)
Set starting index offsets.
Definition: KokkosArray.h:1076
KOKKOS_FUNCTION iterator(T *it)
Definition: KokkosArray.h:307
void createHost(const std::vector< dof_id_type > &n)
Allocate array on host only.
Definition: KokkosArray.h:233
IntRange< T > make_range(T beg, T end)
void copyVector(const std::vector< T > &vector)
Copy a standard vector variable This re-initializes and re-allocates array with the size of the vecto...
Definition: KokkosArray.h:1086
KOKKOS_FUNCTION T & operator()(dof_id_signed_type i0, dof_id_signed_type i1, dof_id_signed_type i2, dof_id_signed_type i3, dof_id_signed_type i4) const
Get an array entry.
Definition: KokkosArray.h:1595
KOKKOS_FUNCTION iterator & operator++()
Definition: KokkosArray.h:312
Array(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
Constructor Initialize and allocate array with given dimensions This allocates both host and device d...
Definition: KokkosArray.h:1393
void allocDevice()
Allocate device data for an initialized array that has not allocated device data. ...
Definition: KokkosArray.h:568
Array(dof_id_type n0)
Constructor Initialize and allocate array with given dimensions This allocates both host and device d...
Definition: KokkosArray.h:1043
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
dof_id_signed_type _d[dimension]
Offset of each dimension.
Definition: KokkosArray.h:362
void offset(dof_id_signed_type d0, dof_id_signed_type d1, dof_id_signed_type d2)
Set starting index offsets.
Definition: KokkosArray.h:1331
void init(dof_id_type n0, dof_id_type n1, dof_id_type n2)
Initialize array with given dimensions but do not allocate.
Definition: KokkosArray.h:1291
Array(const Array< T, 2 > &array)
Copy constructor.
Definition: KokkosArray.h:1165
void destroy(triangulateio &t, IO_Type)
bool _is_host_alloc
Flag whether host data was allocated.
Definition: KokkosArray.h:415
void create(const std::vector< dof_id_type > &n)
Allocate array on host and device.
Definition: KokkosArray.h:228
KOKKOS_FUNCTION T & operator*() const
Definition: KokkosArray.h:310
auto & operator=(const std::set< T > &set)
Copy a standard set variable This allocates and copies to both host and device data.
Definition: KokkosArray.h:1128
auto & operator=(const Array< T, 1 > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:1029
auto index_range(const T &sizable)
void offset(dof_id_signed_type d0, dof_id_signed_type d1, dof_id_signed_type d2, dof_id_signed_type d3, dof_id_signed_type d4)
Set starting index offsets.
Definition: KokkosArray.h:1576
KOKKOS_FUNCTION bool isHostAlias() const
Get whether the host array was aliased.
Definition: KokkosArray.h:149
auto & operator=(const Array< T, 2 > &array)
Shallow copy another Kokkos array.
Definition: KokkosArray.h:1170
std::string prettyCppType(const std::string &cpp_type)
Definition: MooseUtils.C:1147
uint8_t dof_id_type
void aliasHost(T *ptr)
Point the host data to an external data instead of allocating it.
Definition: KokkosArray.h:523