LCOV - code coverage report
Current view: top level - include/kokkos/base - KokkosArray.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 6f668f Lines: 282 339 83.2 %
Date: 2025-09-22 20:01:15 Functions: 851 1167 72.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      41             : /**
      42             :  * The enumerator that dictates the memory copy direction
      43             :  */
      44             : enum class MemcpyKind
      45             : {
      46             :   HOST_TO_HOST,
      47             :   HOST_TO_DEVICE,
      48             :   DEVICE_TO_HOST,
      49             :   DEVICE_TO_DEVICE
      50             : };
      51             : 
      52             : /**
      53             :  * The Kokkos array class
      54             :  */
      55             : template <typename T, unsigned int dimension = 1>
      56             : class Array;
      57             : 
      58             : /**
      59             :  * The type trait that determines the default behavior of copy constructor and deepCopy()
      60             :  * If this type trait is set to true, the copy constructor will call deepCopy(),
      61             :  * and the deepCopy() method will copy-construct each entry.
      62             :  * If this type trait is set to false, the copy constructor will call shallowCopy(),
      63             :  * and the deepCopy() method will do a memory copy.
      64             :  */
      65             : ///@{
      66             : template <typename T>
      67             : struct ArrayDeepCopy
      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             : };
      77             : ///@}
      78             : 
      79             : /**
      80             :  * The base class for Kokkos arrays
      81             :  */
      82             : template <typename T, unsigned int dimension>
      83             : class ArrayBase
      84             : {
      85             : public:
      86             :   /**
      87             :    * Default constructor
      88             :    */
      89     4651494 :   ArrayBase() = default;
      90             : 
      91             :   /**
      92             :    * Copy constructor
      93             :    */
      94    15903817 :   ArrayBase(const ArrayBase<T, dimension> & array)
      95    15903817 :   {
      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       42538 :       deepCopy(array);
     103             :     else
     104    15861279 :       shallowCopy(array);
     105    15903817 :   }
     106             : 
     107             :   /**
     108             :    * Destructor
     109             :    */
     110    20314885 :   ~ArrayBase() { destroy(); }
     111             : 
     112             :   /**
     113             :    * Free all data and reset
     114             :    */
     115             :   void destroy();
     116             : 
     117             :   /**
     118             :    * Shallow copy another Kokkos array
     119             :    * @param array The Kokkos array to be shallow copied
     120             :    */
     121             :   void shallowCopy(const ArrayBase<T, dimension> & array);
     122             : 
     123             :   /**
     124             :    * Get the reference count
     125             :    * @returns The reference count
     126             :    */
     127             :   unsigned int useCount() const { return _counter.use_count(); }
     128             : 
     129             : #ifdef MOOSE_KOKKOS_SCOPE
     130             :   /**
     131             :    * Get whether the array was allocated either on host or device
     132             :    * @returns Whether the array was allocated either on host or device
     133             :    */
     134    16829220 :   KOKKOS_FUNCTION bool isAlloc() const { return _is_host_alloc || _is_device_alloc; }
     135             :   /**
     136             :    * Get whether the array was allocated on host
     137             :    * @returns Whether the array was allocated on host
     138             :    */
     139         466 :   KOKKOS_FUNCTION bool isHostAlloc() const { return _is_host_alloc; }
     140             :   /**
     141             :    * Get whether the array was allocated on device
     142             :    * @returns Whether the array was allocated on device
     143             :    */
     144        1174 :   KOKKOS_FUNCTION bool isDeviceAlloc() const { return _is_device_alloc; }
     145             :   /**
     146             :    * Get whether the host array was aliased
     147             :    * @returns Whether the host array was aliased
     148             :    */
     149             :   KOKKOS_FUNCTION bool isHostAlias() const { return _is_host_alias; }
     150             :   /**
     151             :    * Get whether the device array was aliased
     152             :    * @returns Whether the device array was aliased
     153             :    */
     154             :   KOKKOS_FUNCTION bool isDeviceAlias() const { return _is_device_alias; }
     155             :   /**
     156             :    * Get the total array size
     157             :    * @returns The total array size
     158             :    */
     159   129956488 :   KOKKOS_FUNCTION dof_id_type size() const { return _size; }
     160             :   /**
     161             :    * Get the size of a dimension
     162             :    * @param dim The dimension index
     163             :    * @returns The array size of the dimension
     164             :    */
     165        1400 :   KOKKOS_FUNCTION dof_id_type n(unsigned int dim) const { return _n[dim]; }
     166             :   /**
     167             :    * Get the data pointer
     168             :    * @returns The pointer to the underlying data depending on the architecture this function is
     169             :    * being called on
     170             :    */
     171    18269437 :   KOKKOS_FUNCTION T * data() const
     172             :   {
     173    18269437 :     KOKKOS_IF_ON_HOST(return _host_data;)
     174             : 
     175    18187884 :     return _device_data;
     176             :   }
     177             :   /**
     178             :    * Get the first element
     179             :    * @returns The reference of the first element depending on the architecture this function is
     180             :    * being called on
     181             :    */
     182             :   KOKKOS_FUNCTION T & first() const
     183             :   {
     184             :     KOKKOS_IF_ON_HOST(return _host_data[0];)
     185             : 
     186             :     return _device_data[0];
     187             :   }
     188             :   /**
     189             :    * Get the last element
     190             :    * @returns The reference of the last element depending on the architecture this function is being
     191             :    * called on
     192             :    */
     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             :   }
     199             :   /**
     200             :    * Get an array entry
     201             :    * @param i The dimensionless index
     202             :    * @returns The reference of the entry depending on the architecture this function is being called
     203             :    * on
     204             :    */
     205  1739955062 :   KOKKOS_FUNCTION T & operator[](dof_id_type i) const
     206             :   {
     207             :     KOKKOS_ASSERT(i < _size);
     208             : 
     209  1739955062 :     KOKKOS_IF_ON_HOST(return _host_data[i];)
     210             : 
     211  1734970426 :     return _device_data[i];
     212             :   }
     213             : 
     214             :   /**
     215             :    * Get the host data pointer
     216             :    * @returns The pointer to the underlying host data
     217             :    */
     218      153532 :   T * hostData() const { return _host_data; }
     219             :   /**
     220             :    * Get the device data pointer
     221             :    * @returns The pointer to the underlying device data
     222             :    */
     223      148886 :   T * deviceData() const { return _device_data; }
     224             :   /**
     225             :    * Allocate array on host and device
     226             :    * @param n The vector containing the size of each dimension
     227             :    */
     228             :   void create(const std::vector<dof_id_type> & n) { createInternal<true, true>(n); }
     229             :   /**
     230             :    * Allocate array on host only
     231             :    * @param n The vector containing the size of each dimension
     232             :    */
     233             :   void createHost(const std::vector<dof_id_type> & n) { createInternal<true, false>(n); }
     234             :   /**
     235             :    * Allocate array on device only
     236             :    * @param n The vector containing the size of each dimension
     237             :    */
     238        1506 :   void createDevice(const std::vector<dof_id_type> & n) { createInternal<false, true>(n); }
     239             :   /**
     240             :    * Point the host data to an external data instead of allocating it
     241             :    * @param ptr The pointer to the external host data
     242             :    */
     243             :   void aliasHost(T * ptr);
     244             :   /**
     245             :    * Point the device data to an external data instead of allocating it
     246             :    * @param ptr The pointer to the external device data
     247             :    */
     248             :   void aliasDevice(T * ptr);
     249             :   /**
     250             :    * Apply starting index offsets to each dimension
     251             :    * @param d The vector containing the offset of each dimension
     252             :    */
     253             :   void offset(const std::vector<dof_id_signed_type> & d);
     254             :   /**
     255             :    * Copy data from host to device
     256             :    */
     257             :   void copyToDevice();
     258             :   /**
     259             :    * Copy data from device to host
     260             :    */
     261             :   void copyToHost();
     262             :   /**
     263             :    * Copy data from an external data to this array
     264             :    * @param ptr The pointer to the external data
     265             :    * @param dir The copy direction
     266             :    * @param n The number of entries to copy
     267             :    * @param offset The starting offset of this array
     268             :    */
     269             :   void copyIn(const T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset = 0);
     270             :   /**
     271             :    * Copy data to an external data from this array
     272             :    * @param ptr The pointer to the external data
     273             :    * @param dir The copy direction
     274             :    * @param n The number of entries to copy
     275             :    * @param offset The starting offset of this array
     276             :    */
     277             :   void copyOut(T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset = 0);
     278             :   /**
     279             :    * Copy all the nested Kokkos arrays including self from host to device
     280             :    */
     281             :   void copyToDeviceNested();
     282             :   /**
     283             :    * Deep copy another Kokkos array
     284             :    * If ArrayDeepCopy<T>::value is true, it will copy-construct each entry
     285             :    * If ArrayDeepCopy<T>::value is false, it will do a memory copy
     286             :    * @param array The Kokkos array to be deep copied
     287             :    */
     288             :   void deepCopy(const ArrayBase<T, dimension> & array);
     289             :   /**
     290             :    * Swap with another Kokkos array
     291             :    * @param array The Kokkos array to be swapped
     292             :    */
     293             :   void swap(ArrayBase<T, dimension> & array);
     294             : 
     295             :   /**
     296             :    * Assign a scalar value uniformly
     297             :    * @param scalar The scalar value to be assigned
     298             :    */
     299             :   auto & operator=(const T & scalar);
     300             : 
     301             :   /**
     302             :    * Array iterator
     303             :    */
     304             :   class iterator
     305             :   {
     306             :   public:
     307     2402224 :     KOKKOS_FUNCTION iterator(T * it) : it(it) {}
     308             :     KOKKOS_FUNCTION bool operator==(const iterator & other) const { return it == other.it; }
     309     1391627 :     KOKKOS_FUNCTION bool operator!=(const iterator & other) const { return it != other.it; }
     310      749441 :     KOKKOS_FUNCTION T & operator*() const { return *it; }
     311     1117768 :     KOKKOS_FUNCTION T * operator&() const { return it; }
     312      749405 :     KOKKOS_FUNCTION iterator & operator++()
     313             :     {
     314      749405 :       ++it;
     315      749405 :       return *this;
     316             :     }
     317          36 :     KOKKOS_FUNCTION iterator operator++(int)
     318             :     {
     319          36 :       iterator pre = *this;
     320          36 :       ++it;
     321          36 :       return pre;
     322             :     }
     323             : 
     324             :   private:
     325             :     T * it;
     326             :   };
     327             : 
     328             :   /**
     329             :    * Get the beginning iterator
     330             :    * @returns The beginning iterator
     331             :    */
     332     1201118 :   KOKKOS_FUNCTION iterator begin() const
     333             :   {
     334     1201118 :     KOKKOS_IF_ON_HOST(return iterator(_host_data);)
     335             : 
     336      557590 :     return iterator(_device_data);
     337             :   }
     338             :   /**
     339             :    * Get the end iterator
     340             :    * @returns The end iterator
     341             :    */
     342     1201106 :   KOKKOS_FUNCTION iterator end() const
     343             :   {
     344     1201106 :     KOKKOS_IF_ON_HOST(return iterator(_host_data + _size);)
     345             : 
     346      557590 :     return iterator(_device_data + _size);
     347             :   }
     348             : #endif
     349             : 
     350             : protected:
     351             :   /**
     352             :    * Size of each dimension
     353             :    */
     354             :   dof_id_type _n[dimension] = {0};
     355             :   /**
     356             :    * Stride of each dimension
     357             :    */
     358             :   dof_id_type _s[dimension] = {0};
     359             :   /**
     360             :    * Offset of each dimension
     361             :    */
     362             :   dof_id_signed_type _d[dimension] = {0};
     363             : 
     364             : #ifdef MOOSE_KOKKOS_SCOPE
     365             :   /**
     366             :    * The internal method to initialize and allocate this array
     367             :    * @tparam host Whether host data will be allocated
     368             :    * @tparam device Whether device data will be allocated
     369             :    * @param n The vector containing the size of each dimension
     370             :    */
     371             :   template <bool host, bool device>
     372             :   void createInternal(const std::vector<dof_id_type> & n);
     373             :   /**
     374             :    * The internal method to initialize and allocate this array
     375             :    * @param n The vector containing the size of each dimension
     376             :    * @param host The flag whether host data will be allocated
     377             :    * @param device The flag whether device data will be allocated
     378             :    */
     379             :   void createInternal(const std::vector<dof_id_type> & n, bool host, bool device);
     380             :   /**
     381             :    * The internal method to perform a memory copy
     382             :    * @tparam TargetSpace The Kokkos memory space of target data
     383             :    * @tparam Sourcespace The Kokkos memory space of source data
     384             :    * @param target The pointer to the target data
     385             :    * @param source The pointer to the source data
     386             :    * @param n The number of entries to copy
     387             :    */
     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             :   /**
     395             :    * Allocate host data for an initialized array that has not allocated host data
     396             :    */
     397             :   void allocHost();
     398             :   /**
     399             :    * Allocate device data for an initialized array that has not allocated device data
     400             :    */
     401             :   void allocDevice();
     402             : #endif
     403             : 
     404             :   /**
     405             :    * Reference counter
     406             :    */
     407             :   std::shared_ptr<unsigned int> _counter;
     408             :   /**
     409             :    * Flag whether array was initialized
     410             :    */
     411             :   bool _is_init = false;
     412             :   /**
     413             :    * Flag whether host data was allocated
     414             :    */
     415             :   bool _is_host_alloc = false;
     416             :   /**
     417             :    * Flag whether device data was allocated
     418             :    */
     419             :   bool _is_device_alloc = false;
     420             :   /**
     421             :    * Flag whether the host data points to an external data
     422             :    */
     423             :   bool _is_host_alias = false;
     424             :   /**
     425             :    * Flag whether the device data points to an external data
     426             :    */
     427             :   bool _is_device_alias = false;
     428             :   /**
     429             :    * Host data
     430             :    */
     431             :   T * _host_data = nullptr;
     432             :   /**
     433             :    * Device data
     434             :    */
     435             :   T * _device_data = nullptr;
     436             :   /**
     437             :    * Total size
     438             :    */
     439             :   dof_id_type _size = 0;
     440             : };
     441             : 
     442             : template <typename T, unsigned int dimension>
     443             : void
     444    37341864 : ArrayBase<T, dimension>::destroy()
     445             : {
     446    37341864 :   if (!_counter)
     447    22309214 :     return;
     448             : 
     449    15032650 :   if (_counter.use_count() > 1)
     450             :   {
     451    14711142 :     _host_data = nullptr;
     452    14711142 :     _device_data = nullptr;
     453             :   }
     454      321508 :   else if (_counter.use_count() == 1)
     455             :   {
     456      321508 :     if (_is_host_alloc && !_is_host_alias)
     457             :     {
     458             :       if constexpr (std::is_default_constructible<T>::value)
     459             :         // Allocated by new
     460      608738 :         delete[] _host_data;
     461             :       else
     462             :       {
     463             :         // Allocated by malloc
     464        2031 :         for (dof_id_type i = 0; i < _size; ++i)
     465        1354 :           _host_data[i].~T();
     466             : 
     467         677 :         std::free(_host_data);
     468             :       }
     469             :     }
     470             : 
     471      321508 :     if (_is_device_alloc && !_is_device_alias)
     472      321496 :       Moose::Kokkos::free(_device_data);
     473             :   }
     474             : 
     475    15032650 :   _size = 0;
     476             : 
     477    37728173 :   for (unsigned int i = 0; i < dimension; ++i)
     478             :   {
     479    22695523 :     _n[i] = 0;
     480    22695523 :     _s[i] = 0;
     481    22695523 :     _d[i] = 0;
     482             :   }
     483             : 
     484    15032650 :   _is_init = false;
     485    15032650 :   _is_host_alloc = false;
     486    15032650 :   _is_device_alloc = false;
     487    15032650 :   _is_host_alias = false;
     488    15032650 :   _is_device_alias = false;
     489             : 
     490    15032650 :   _counter.reset();
     491             : }
     492             : 
     493             : template <typename T, unsigned int dimension>
     494             : void
     495    16684663 : ArrayBase<T, dimension>::shallowCopy(const ArrayBase<T, dimension> & array)
     496             : {
     497    16684663 :   destroy();
     498             : 
     499    16684663 :   _counter = array._counter;
     500             : 
     501    16684663 :   _size = array._size;
     502             : 
     503    41240945 :   for (unsigned int i = 0; i < dimension; ++i)
     504             :   {
     505    24556282 :     _n[i] = array._n[i];
     506    24556282 :     _s[i] = array._s[i];
     507    24556282 :     _d[i] = array._d[i];
     508             :   }
     509             : 
     510    16684663 :   _is_init = array._is_init;
     511    16684663 :   _is_host_alloc = array._is_host_alloc;
     512    16684663 :   _is_device_alloc = array._is_device_alloc;
     513    16684663 :   _is_host_alias = array._is_host_alias;
     514    16684663 :   _is_device_alias = array._is_device_alias;
     515             : 
     516    16684663 :   _host_data = array._host_data;
     517    16684663 :   _device_data = array._device_data;
     518    16684663 : }
     519             : 
     520             : #ifdef MOOSE_KOKKOS_SCOPE
     521             : template <typename T, unsigned int dimension>
     522             : void
     523      173901 : ArrayBase<T, dimension>::aliasHost(T * ptr)
     524             : {
     525      173901 :   if (!_is_init)
     526           0 :     mooseError("Kokkos array error: attempted to alias host data before array initialization.");
     527             : 
     528      173901 :   if (_is_host_alloc && !_is_host_alias)
     529           0 :     mooseError("Kokkos array error: cannot alias host data because host data was not aliased.");
     530             : 
     531      173901 :   _host_data = ptr;
     532      173901 :   _is_host_alloc = true;
     533      173901 :   _is_host_alias = true;
     534      173901 : }
     535             : 
     536             : template <typename T, unsigned int dimension>
     537             : void
     538          32 : ArrayBase<T, dimension>::aliasDevice(T * ptr)
     539             : {
     540          32 :   if (!_is_init)
     541           0 :     mooseError("Kokkos array error: attempted to alias device data before array initialization.");
     542             : 
     543          32 :   if (_is_device_alloc && !_is_device_alias)
     544           0 :     mooseError("Kokkos array error: cannot alias device data because device data was not aliased.");
     545             : 
     546          32 :   _device_data = ptr;
     547          32 :   _is_device_alloc = true;
     548          32 :   _is_device_alias = true;
     549          32 : }
     550             : 
     551             : template <typename T, unsigned int dimension>
     552             : void
     553      313996 : ArrayBase<T, dimension>::allocHost()
     554             : {
     555      313996 :   if (_is_host_alloc)
     556           0 :     return;
     557             : 
     558             :   if constexpr (std::is_default_constructible<T>::value)
     559      798845 :     _host_data = new T[_size];
     560             :   else
     561         693 :     _host_data = static_cast<T *>(std::malloc(_size * sizeof(T)));
     562             : 
     563      313996 :   _is_host_alloc = true;
     564             : }
     565             : 
     566             : template <typename T, unsigned int dimension>
     567             : void
     568      325093 : ArrayBase<T, dimension>::allocDevice()
     569             : {
     570      325093 :   if (_is_device_alloc)
     571           0 :     return;
     572             : 
     573      325093 :   _device_data =
     574      255726 :       static_cast<T *>(::Kokkos::kokkos_malloc<ExecSpace::memory_space>(_size * sizeof(T)));
     575             : 
     576      325093 :   _is_device_alloc = true;
     577             : }
     578             : 
     579             : template <typename T, unsigned int dimension>
     580             : template <bool host, bool device>
     581             : void
     582      325105 : ArrayBase<T, dimension>::createInternal(const std::vector<dof_id_type> & n)
     583             : {
     584      325105 :   if (n.size() != dimension)
     585           0 :     mooseError("Kokkos array error: the number of dimensions provided (",
     586           0 :                n.size(),
     587             :                ") must match the array dimension (",
     588             :                dimension,
     589             :                ").");
     590             : 
     591      325105 :   if (_counter)
     592        6721 :     destroy();
     593             : 
     594      325105 :   _counter = std::make_shared<unsigned int>();
     595             : 
     596      325105 :   _size = 1;
     597      325105 :   _s[0] = 1;
     598             : 
     599      695363 :   for (const auto i : make_range(dimension))
     600             :   {
     601      370258 :     _n[i] = n[i];
     602      370258 :     _size *= n[i];
     603             : 
     604      370258 :     if (i)
     605       45153 :       _s[i] = _s[i - 1] * _n[i - 1];
     606             :   }
     607             : 
     608             :   if constexpr (host)
     609      313996 :     allocHost();
     610             : 
     611             :   if constexpr (device)
     612      325093 :     allocDevice();
     613             : 
     614      325105 :   _is_init = true;
     615      325105 : }
     616             : 
     617             : template <typename T, unsigned int dimension>
     618             : void
     619       43022 : ArrayBase<T, dimension>::createInternal(const std::vector<dof_id_type> & n, bool host, bool device)
     620             : {
     621       43022 :   if (host && device)
     622       42538 :     createInternal<true, true>(n);
     623         484 :   else if (host && !device)
     624           0 :     createInternal<true, false>(n);
     625         484 :   else if (!host && device)
     626         484 :     createInternal<false, true>(n);
     627             :   else
     628           0 :     createInternal<false, false>(n);
     629       43022 : }
     630             : 
     631             : template <typename T, unsigned int dimension>
     632             : template <typename TargetSpace, typename SourceSpace>
     633             : void
     634     1068146 : ArrayBase<T, dimension>::copyInternal(T * target, const T * source, dof_id_type n)
     635             : {
     636     1068146 :   ::Kokkos::Impl::DeepCopy<TargetSpace, SourceSpace>(target, source, n * sizeof(T));
     637     1068146 :   ::Kokkos::fence();
     638     1068146 : }
     639             : 
     640             : template <typename T, unsigned int dimension>
     641             : void
     642        1662 : ArrayBase<T, dimension>::offset(const std::vector<dof_id_signed_type> & d)
     643             : {
     644        1662 :   if (d.size() > dimension)
     645           0 :     mooseError("Kokkos array error: the number of offsets provided (",
     646           0 :                d.size(),
     647             :                ") cannot be larger than the array dimension (",
     648             :                dimension,
     649             :                ").");
     650             : 
     651        3324 :   for (const auto i : index_range(d))
     652        1662 :     _d[i] = d[i];
     653        1662 : }
     654             : 
     655             : template <typename T, unsigned int dimension>
     656             : void
     657      791664 : ArrayBase<T, dimension>::copyToDevice()
     658             : {
     659             :   // If host side memory is not allocated, do nothing
     660      791664 :   if (!_is_host_alloc)
     661       43677 :     return;
     662             : 
     663             :   // If device side memory is not allocated,
     664      747987 :   if (!_is_device_alloc)
     665             :   {
     666           0 :     if (_counter.use_count() == 1)
     667             :       // allocate memory if this array is not shared with other arrays
     668           0 :       allocDevice();
     669             :     else
     670             :       // print error if this array is shared with other arrays
     671           0 :       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      747987 :   copyInternal<MemSpace, ::Kokkos::HostSpace>(_device_data, _host_data, _size);
     677             : }
     678             : 
     679             : template <typename T, unsigned int dimension>
     680             : void
     681      169633 : ArrayBase<T, dimension>::copyToHost()
     682             : {
     683             :   // If device side memory is not allocated, do nothing
     684      169633 :   if (!_is_device_alloc)
     685           0 :     return;
     686             : 
     687             :   // If host side memory is not allocated,
     688      169633 :   if (!_is_host_alloc)
     689             :   {
     690           0 :     if (_counter.use_count() == 1)
     691             :       // allocate memory if this array is not shared with other arrays
     692           0 :       allocHost();
     693             :     else
     694             :       // print error if this array is shared with other arrays
     695           0 :       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      169633 :   copyInternal<::Kokkos::HostSpace, MemSpace>(_host_data, _device_data, _size);
     701             : }
     702             : 
     703             : template <typename T, unsigned int dimension>
     704             : void
     705         226 : ArrayBase<T, dimension>::copyIn(const T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset)
     706             : {
     707         226 :   if (n > _size)
     708           0 :     mooseError("Kokkos array error: cannot copyin data larger than the array size.");
     709             : 
     710         226 :   if (offset > _size)
     711           0 :     mooseError("Kokkos array error: offset cannot be larger than the array size.");
     712             : 
     713         226 :   if (dir == MemcpyKind::HOST_TO_HOST)
     714             :   {
     715             :     // If host side memory is not allocated, do nothing
     716           0 :     if (!_is_host_alloc)
     717           0 :       return;
     718             : 
     719             :     // Copy from host to host
     720           0 :     copyInternal<::Kokkos::HostSpace, ::Kokkos::HostSpace>(_host_data + offset, ptr, n);
     721             :   }
     722         226 :   else if (dir == MemcpyKind::HOST_TO_DEVICE)
     723             :   {
     724             :     // If device side memory is not allocated, do nothing
     725         226 :     if (!_is_device_alloc)
     726           0 :       return;
     727             : 
     728             :     // Copy from host to device
     729         226 :     copyInternal<MemSpace, ::Kokkos::HostSpace>(_device_data + offset, ptr, n);
     730             :   }
     731           0 :   else if (dir == MemcpyKind::DEVICE_TO_HOST)
     732             :   {
     733             :     // If host side memory is not allocated, do nothing
     734           0 :     if (!_is_host_alloc)
     735           0 :       return;
     736             : 
     737             :     // Copy from device to host
     738           0 :     copyInternal<::Kokkos::HostSpace, MemSpace>(_host_data + offset, ptr, n);
     739             :   }
     740           0 :   else if (dir == MemcpyKind::DEVICE_TO_DEVICE)
     741             :   {
     742             :     // If device side memory is not allocated, do nothing
     743           0 :     if (!_is_device_alloc)
     744           0 :       return;
     745             : 
     746             :     // Copy from device to device
     747           0 :     copyInternal<MemSpace, MemSpace>(_device_data + offset, ptr, n);
     748             :   }
     749             : }
     750             : 
     751             : template <typename T, unsigned int dimension>
     752             : void
     753         934 : ArrayBase<T, dimension>::copyOut(T * ptr, MemcpyKind dir, dof_id_type n, dof_id_type offset)
     754             : {
     755         934 :   if (n > _size)
     756           0 :     mooseError("Kokkos array error: cannot copyout data larger than the array size.");
     757             : 
     758         934 :   if (offset > _size)
     759           0 :     mooseError("Kokkos array error: offset cannot be larger than the array size.");
     760             : 
     761         934 :   if (dir == MemcpyKind::HOST_TO_HOST)
     762             :   {
     763             :     // If host side memory is not allocated, do nothing
     764           0 :     if (!_is_host_alloc)
     765           0 :       return;
     766             : 
     767             :     // Copy from host to host
     768           0 :     copyInternal<::Kokkos::HostSpace, ::Kokkos::HostSpace>(ptr, _host_data + offset, n);
     769             :   }
     770         934 :   else if (dir == MemcpyKind::HOST_TO_DEVICE)
     771             :   {
     772             :     // If host side memory is not allocated, do nothing
     773           0 :     if (!_is_host_alloc)
     774           0 :       return;
     775             : 
     776             :     // Copy from host to device
     777           0 :     copyInternal<MemSpace, ::Kokkos::HostSpace>(ptr, _host_data + offset, n);
     778             :   }
     779         934 :   else if (dir == MemcpyKind::DEVICE_TO_HOST)
     780             :   {
     781             :     // If device side memory is not allocated, do nothing
     782         934 :     if (!_is_device_alloc)
     783           0 :       return;
     784             : 
     785             :     // Copy from device to host
     786         934 :     copyInternal<::Kokkos::HostSpace, MemSpace>(ptr, _device_data + offset, n);
     787             :   }
     788           0 :   else if (dir == MemcpyKind::DEVICE_TO_DEVICE)
     789             :   {
     790             :     // If device side memory is not allocated, do nothing
     791           0 :     if (!_is_device_alloc)
     792           0 :       return;
     793             : 
     794             :     // Copy from device to device
     795           0 :     copyInternal<MemSpace, MemSpace>(ptr, _device_data + offset, n);
     796             :   }
     797             : }
     798             : 
     799             : template <typename T>
     800             : void
     801      884684 : copyToDeviceInner(T & /* data */)
     802             : {
     803      884684 : }
     804             : 
     805             : template <typename T, unsigned int dimension>
     806             : void
     807       83819 : copyToDeviceInner(Array<T, dimension> & data)
     808             : {
     809       83819 :   data.copyToDeviceNested();
     810       83819 : }
     811             : 
     812             : template <typename T, unsigned int dimension>
     813             : void
     814      103922 : ArrayBase<T, dimension>::copyToDeviceNested()
     815             : {
     816     1072425 :   for (unsigned int i = 0; i < _size; ++i)
     817      968503 :     copyToDeviceInner(_host_data[i]);
     818             : 
     819      103922 :   copyToDevice();
     820      103922 : }
     821             : 
     822             : template <typename T, unsigned int dimension>
     823             : void
     824       43022 : ArrayBase<T, dimension>::deepCopy(const ArrayBase<T, dimension> & array)
     825             : {
     826       42538 :   if (ArrayDeepCopy<T>::value && !array._is_host_alloc)
     827           0 :     mooseError(
     828             :         "Kokkos array error: cannot deep copy using constructor from array without host data.");
     829             : 
     830      129066 :   std::vector<dof_id_type> n(std::begin(array._n), std::end(array._n));
     831             : 
     832       43022 :   createInternal(n, array._is_host_alloc, array._is_device_alloc);
     833             : 
     834             :   if constexpr (ArrayDeepCopy<T>::value)
     835             :   {
     836       85212 :     for (dof_id_type i = 0; i < _size; ++i)
     837       42674 :       new (_host_data + i) T(array._host_data[i]);
     838             : 
     839       42538 :     copyToDevice();
     840             :   }
     841             :   else
     842             :   {
     843         484 :     if (_is_host_alloc)
     844           0 :       std::memcpy(_host_data, array._host_data, _size * sizeof(T));
     845             : 
     846         484 :     if (_is_device_alloc)
     847         484 :       copyInternal<MemSpace, MemSpace>(_device_data, array._device_data, _size);
     848             :   }
     849             : 
     850       86044 :   for (unsigned int i = 0; i < dimension; ++i)
     851             :   {
     852       43022 :     _d[i] = array._d[i];
     853       43022 :     _s[i] = array._s[i];
     854             :   }
     855       43022 : }
     856             : 
     857             : template <typename T, unsigned int dimension>
     858             : void
     859        1868 : ArrayBase<T, dimension>::swap(ArrayBase<T, dimension> & array)
     860             : {
     861        1868 :   ArrayBase<T, dimension> clone;
     862             : 
     863        1868 :   clone.shallowCopy(*this);
     864        1868 :   this->shallowCopy(array);
     865        1868 :   array.shallowCopy(clone);
     866        1868 : }
     867             : 
     868             : template <typename T, unsigned int dimension>
     869             : auto &
     870      217533 : ArrayBase<T, dimension>::operator=(const T & scalar)
     871             : {
     872      217533 :   if (_is_host_alloc)
     873      217501 :     std::fill_n(_host_data, _size, scalar);
     874             : 
     875      217533 :   if (_is_device_alloc)
     876             :   {
     877      217533 :     ::Kokkos::View<T *, MemSpace, ::Kokkos::MemoryTraits<::Kokkos::Unmanaged>> data(_device_data,
     878             :                                                                                     _size);
     879      217533 :     ::Kokkos::Experimental::fill_n(ExecSpace(), data, _size, scalar);
     880      217533 :   }
     881             : 
     882      217533 :   return *this;
     883             : }
     884             : 
     885             : template <typename T, unsigned int dimension>
     886             : void
     887         934 : dataStore(std::ostream & stream, Array<T, dimension> & array, void * context)
     888             : {
     889             :   using ::dataStore;
     890             : 
     891         934 :   bool is_alloc = array.isAlloc();
     892         934 :   dataStore(stream, is_alloc, nullptr);
     893             : 
     894         934 :   if (!is_alloc)
     895           0 :     return;
     896             : 
     897         934 :   std::string type = typeid(T).name();
     898         934 :   dataStore(stream, type, nullptr);
     899             : 
     900         934 :   unsigned int dim = dimension;
     901         934 :   dataStore(stream, dim, nullptr);
     902             : 
     903        1868 :   for (unsigned int dim = 0; dim < dimension; ++dim)
     904             :   {
     905         934 :     auto n = array.n(dim);
     906         934 :     dataStore(stream, n, nullptr);
     907             :   }
     908             : 
     909         934 :   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         934 :     T * data = static_cast<T *>(std::malloc(array.size() * sizeof(T)));
     916             : 
     917         934 :     array.copyOut(data, MemcpyKind::DEVICE_TO_HOST, array.size());
     918             : 
     919       66166 :     for (dof_id_type i = 0; i < array.size(); ++i)
     920       65232 :       dataStore(stream, data[i], context);
     921             : 
     922         934 :     std::free(data);
     923             :   }
     924             :   else
     925           0 :     for (auto & value : array)
     926           0 :       dataStore(stream, value, context);
     927         934 : }
     928             : 
     929             : template <typename T, unsigned int dimension>
     930             : void
     931         466 : dataLoad(std::istream & stream, Array<T, dimension> & array, void * context)
     932             : {
     933             :   using ::dataLoad;
     934             : 
     935             :   bool is_alloc;
     936         466 :   dataLoad(stream, is_alloc, nullptr);
     937             : 
     938         466 :   if (!is_alloc)
     939           0 :     return;
     940             : 
     941         466 :   std::string from_type_name;
     942         466 :   dataLoad(stream, from_type_name, nullptr);
     943             : 
     944         466 :   if (from_type_name != typeid(T).name())
     945           0 :     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 '",
     948             :                MooseUtils::prettyCppType(libMesh::demangle(typeid(T).name())),
     949             :                "'.");
     950             : 
     951             :   unsigned int from_dimension;
     952         466 :   dataLoad(stream, from_dimension, nullptr);
     953             : 
     954         466 :   if (from_dimension != dimension)
     955           0 :     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         932 :   std::vector<dof_id_type> from_n(dimension);
     962         466 :   std::vector<dof_id_type> n(dimension);
     963             : 
     964         932 :   for (unsigned int dim = 0; dim < dimension; ++dim)
     965             :   {
     966         466 :     dataLoad(stream, from_n[dim], nullptr);
     967         466 :     n[dim] = array.n(dim);
     968             :   }
     969             : 
     970         466 :   if (from_n != n)
     971           0 :     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         466 :   if (array.isHostAlloc())
     978             :   {
     979        2106 :     for (auto & value : array)
     980        1626 :       dataLoad(stream, value, context);
     981             : 
     982         240 :     if (array.isDeviceAlloc())
     983         240 :       array.copyToDevice();
     984             :   }
     985             :   else
     986             :   {
     987         226 :     std::vector<T> data(array.size());
     988             : 
     989       31442 :     for (auto & value : data)
     990       31216 :       dataLoad(stream, value, context);
     991             : 
     992         226 :     array.copyIn(data.data(), MemcpyKind::HOST_TO_DEVICE, array.size());
     993         226 :   }
     994         466 : }
     995             : #endif
     996             : 
     997             : /**
     998             :  * The specialization of the Kokkos array class for each dimension.
     999             :  * All array data that needs to be accessed on device in Kokkos objects should use this class.
    1000             :  * If the array is populated on host and is to be accessed on device, make sure to call
    1001             :  * copyToDevice() after populating data. For a nested Kokkos array, either copyToDeviceNested()
    1002             :  * should be called for the outermost array or copyToDevice() should be called for each instance of
    1003             :  * Kokkos array from the innermost to the outermost. Do not store this object as reference in your
    1004             :  * Kokkos object if it is used on device, because the reference refers to a host object and
    1005             :  * therefore is not accessible on device. If storing it as a reference is required, see
    1006             :  * ReferenceWrapper.
    1007             :  */
    1008             : ///@{
    1009             : 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:
    1017             :   /**
    1018             :    * Default constructor
    1019             :    */
    1020     3679367 :   Array() = default;
    1021             :   /**
    1022             :    * Copy constructor
    1023             :    */
    1024     9654893 :   Array(const Array<T, 1> & array) : ArrayBase<T, 1>(array) {}
    1025             :   /**
    1026             :    * Shallow copy another Kokkos array
    1027             :    * @param array The Kokkos array to be shallow copied
    1028             :    */
    1029      817780 :   auto & operator=(const Array<T, 1> & array)
    1030             :   {
    1031      817780 :     this->shallowCopy(array);
    1032             : 
    1033      817780 :     return *this;
    1034             :   }
    1035             : 
    1036             : #ifdef MOOSE_KOKKOS_SCOPE
    1037             :   /**
    1038             :    * Constructor
    1039             :    * Initialize and allocate array with given dimensions
    1040             :    * This allocates both host and device data
    1041             :    * @param n0 The first dimension size
    1042             :    */
    1043          24 :   Array(dof_id_type n0) { create(n0); }
    1044             :   /**
    1045             :    * Constructor
    1046             :    * Initialize and allocate array by copying a standard vector variable
    1047             :    * This allocates and copies to both host and device data
    1048             :    * @param vector The standard vector variable to copy
    1049             :    */
    1050         414 :   Array(const std::vector<T> & vector) { *this = vector; }
    1051             : 
    1052             :   /**
    1053             :    * Initialize array with given dimensions but do not allocate
    1054             :    * @param n0 The first dimension size
    1055             :    */
    1056          36 :   void init(dof_id_type n0) { this->template createInternal<false, false>({n0}); }
    1057             :   /**
    1058             :    * Initialize and allocate array with given dimensions on host and device
    1059             :    * @param n0 The first dimension size
    1060             :    */
    1061      244977 :   void create(dof_id_type n0) { this->template createInternal<true, true>({n0}); }
    1062             :   /**
    1063             :    * Initialize and allocate array with given dimensions on host only
    1064             :    * @param n0 The first dimension size
    1065             :    */
    1066             :   void createHost(dof_id_type n0) { this->template createInternal<true, false>({n0}); }
    1067             :   /**
    1068             :    * Initialize and allocate array with given dimensions on device only
    1069             :    * @param n0 The first dimension size
    1070             :    */
    1071       27321 :   void createDevice(dof_id_type n0) { this->template createInternal<false, true>({n0}); }
    1072             :   /**
    1073             :    * Set starting index offsets
    1074             :    * @param d0 The first dimension offset
    1075             :    */
    1076        4986 :   void offset(dof_id_signed_type d0) { ArrayBase<T, 1>::offset({d0}); }
    1077             : 
    1078             :   /**
    1079             :    * Copy a standard vector variable
    1080             :    * This re-initializes and re-allocates array with the size of the vector
    1081             :    * @tparam host Whether to allocate and copy to the host data
    1082             :    * @tparam device Whether to allocate and copy to the device data
    1083             :    * @param vector The standard vector variable to copy
    1084             :    */
    1085             :   template <bool host, bool device>
    1086      148882 :   void copyVector(const std::vector<T> & vector)
    1087             :   {
    1088      297764 :     this->template createInternal<host, device>({static_cast<dof_id_type>(vector.size())});
    1089             : 
    1090             :     if (host)
    1091      148882 :       std::memcpy(this->hostData(), vector.data(), this->size() * sizeof(T));
    1092             : 
    1093             :     if (device)
    1094      148882 :       this->template copyInternal<MemSpace, ::Kokkos::HostSpace>(
    1095             :           this->deviceData(), vector.data(), this->size());
    1096      148882 :   }
    1097             :   /**
    1098             :    * Copy a standard set variable
    1099             :    * This re-initializes and re-allocates array with the size of the set
    1100             :    * @tparam host Whether to allocate and copy to the host data
    1101             :    * @tparam device Whether to allocate and copy to the device data
    1102             :    * @param set The standard set variable to copy
    1103             :    */
    1104             :   template <bool host, bool device>
    1105      145254 :   void copySet(const std::set<T> & set)
    1106             :   {
    1107      145254 :     std::vector<T> vector(set.begin(), set.end());
    1108             : 
    1109      145254 :     copyVector<host, device>(vector);
    1110      145254 :   }
    1111             : 
    1112             :   /**
    1113             :    * Copy a standard vector variable
    1114             :    * This allocates and copies to both host and device data
    1115             :    * @param vector The standard vector variable to copy
    1116             :    */
    1117        3628 :   auto & operator=(const std::vector<T> & vector)
    1118             :   {
    1119        3628 :     copyVector<true, true>(vector);
    1120             : 
    1121        3628 :     return *this;
    1122             :   }
    1123             :   /**
    1124             :    * Copy a standard set variable
    1125             :    * This allocates and copies to both host and device data
    1126             :    * @param set The standard set variable to copy
    1127             :    */
    1128      145254 :   auto & operator=(const std::set<T> & set)
    1129             :   {
    1130      145254 :     copySet<true, true>(set);
    1131             : 
    1132      145254 :     return *this;
    1133             :   }
    1134             : 
    1135             :   /**
    1136             :    * Get an array entry
    1137             :    * @param i0 The first dimension index
    1138             :    * @returns The reference of the entry depending on the architecture this function is being
    1139             :    * called on
    1140             :    */
    1141    65499539 :   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    65499539 :     return this->operator[](i0 - _d[0]);
    1146             :   }
    1147             : #endif
    1148             : };
    1149             : 
    1150             : template <typename T>
    1151             : class Array<T, 2> : public ArrayBase<T, 2>
    1152             : {
    1153             : #ifdef MOOSE_KOKKOS_SCOPE
    1154             :   usingKokkosArrayBaseMembers(T, 2);
    1155             : #endif
    1156             : 
    1157             : public:
    1158             :   /**
    1159             :    * Default constructor
    1160             :    */
    1161      754030 :   Array() = default;
    1162             :   /**
    1163             :    * Copy constructor
    1164             :    */
    1165     4626229 :   Array(const Array<T, 2> & array) : ArrayBase<T, 2>(array) {}
    1166             :   /**
    1167             :    * Shallow copy another Kokkos array
    1168             :    * @param array The Kokkos array to be shallow copied
    1169             :    */
    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             :   /**
    1179             :    * Constructor
    1180             :    * Initialize and allocate array with given dimensions
    1181             :    * This allocates both host and device data
    1182             :    * @param n0 The first dimension size
    1183             :    * @param n1 The second dimension size
    1184             :    */
    1185             :   Array(dof_id_type n0, dof_id_type n1) { create(n0, n1); }
    1186             : 
    1187             :   /**
    1188             :    * Initialize array with given dimensions but do not allocate
    1189             :    * @param n0 The first dimension size
    1190             :    * @param n1 The second dimension size
    1191             :    */
    1192             :   void init(dof_id_type n0, dof_id_type n1)
    1193             :   {
    1194             :     this->template createInternal<false, false>({n0, n1});
    1195             :   }
    1196             :   /**
    1197             :    * Initialize and allocate array with given dimensions on host and device
    1198             :    * @param n0 The first dimension size
    1199             :    * @param n1 The second dimension size
    1200             :    */
    1201       36753 :   void create(dof_id_type n0, dof_id_type n1)
    1202             :   {
    1203       73506 :     this->template createInternal<true, true>({n0, n1});
    1204       36753 :   }
    1205             :   /**
    1206             :    * Initialize and allocate array with given dimensions on host only
    1207             :    * @param n0 The first dimension size
    1208             :    * @param n1 The second dimension size
    1209             :    */
    1210             :   void createHost(dof_id_type n0, dof_id_type n1)
    1211             :   {
    1212             :     this->template createInternal<true, false>({n0, n1});
    1213             :   }
    1214             :   /**
    1215             :    * Initialize and allocate array with given dimensions on device only
    1216             :    * @param n0 The first dimension size
    1217             :    * @param n1 The second dimension size
    1218             :    */
    1219             :   void createDevice(dof_id_type n0, dof_id_type n1)
    1220             :   {
    1221             :     this->template createInternal<false, true>({n0, n1});
    1222             :   }
    1223             :   /**
    1224             :    * Set starting index offsets
    1225             :    * @param d0 The first dimension offset
    1226             :    * @param d1 The second dimension offset
    1227             :    */
    1228             :   void offset(dof_id_signed_type d0, dof_id_signed_type d1) { ArrayBase<T, 2>::offset({d0, d1}); }
    1229             : 
    1230             :   /**
    1231             :    * Get an array entry
    1232             :    * @param i0 The first dimension index
    1233             :    * @param i1 The second dimension index
    1234             :    * @returns The reference of the entry depending on the architecture this function is being called
    1235             :    * on
    1236             :    */
    1237   482366520 :   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   482366520 :     return this->operator[](i0 - _d[0] + (i1 - _d[1]) * _s[1]);
    1243             :   }
    1244             : #endif
    1245             : };
    1246             : 
    1247             : template <typename T>
    1248             : class Array<T, 3> : public ArrayBase<T, 3>
    1249             : {
    1250             : #ifdef MOOSE_KOKKOS_SCOPE
    1251             :   usingKokkosArrayBaseMembers(T, 3);
    1252             : #endif
    1253             : 
    1254             : public:
    1255             :   /**
    1256             :    * Default constructor
    1257             :    */
    1258      217659 :   Array() = default;
    1259             :   /**
    1260             :    * Copy constructor
    1261             :    */
    1262     1622695 :   Array(const Array<T, 3> & array) : ArrayBase<T, 3>(array) {}
    1263             :   /**
    1264             :    * Shallow copy another Kokkos array
    1265             :    * @param array The Kokkos array to be shallow copied
    1266             :    */
    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             :   /**
    1276             :    * Constructor
    1277             :    * Initialize and allocate array with given dimensions
    1278             :    * This allocates both host and device data
    1279             :    * @param n0 The first dimension size
    1280             :    * @param n1 The second dimension size
    1281             :    * @param n2 The third dimension size
    1282             :    */
    1283             :   Array(dof_id_type n0, dof_id_type n1, dof_id_type n2) { create(n0, n1, n2); }
    1284             : 
    1285             :   /**
    1286             :    * Initialize array with given dimensions but do not allocate
    1287             :    * @param n0 The first dimension size
    1288             :    * @param n1 The second dimension size
    1289             :    * @param n2 The third dimension size
    1290             :    */
    1291             :   void init(dof_id_type n0, dof_id_type n1, dof_id_type n2)
    1292             :   {
    1293             :     this->template createInternal<false, false>({n0, n1, n2});
    1294             :   }
    1295             :   /**
    1296             :    * Initialize and allocate array with given dimensions on host and device
    1297             :    * @param n0 The first dimension size
    1298             :    * @param n1 The second dimension size
    1299             :    * @param n2 The third dimension size
    1300             :    */
    1301        4164 :   void create(dof_id_type n0, dof_id_type n1, dof_id_type n2)
    1302             :   {
    1303        8328 :     this->template createInternal<true, true>({n0, n1, n2});
    1304        4164 :   }
    1305             :   /**
    1306             :    * Initialize and allocate array with given dimensions on host only
    1307             :    * @param n0 The first dimension size
    1308             :    * @param n1 The second dimension size
    1309             :    * @param n2 The third dimension size
    1310             :    */
    1311             :   void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2)
    1312             :   {
    1313             :     this->template createInternal<true, false>({n0, n1, n2});
    1314             :   }
    1315             :   /**
    1316             :    * Initialize and allocate array with given dimensions on device only
    1317             :    * @param n0 The first dimension size
    1318             :    * @param n1 The second dimension size
    1319             :    * @param n2 The third dimension size
    1320             :    */
    1321             :   void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2)
    1322             :   {
    1323             :     this->template createInternal<false, true>({n0, n1, n2});
    1324             :   }
    1325             :   /**
    1326             :    * Set starting index offsets
    1327             :    * @param d0 The first dimension offset
    1328             :    * @param d1 The second dimension offset
    1329             :    * @param d2 The third dimension offset
    1330             :    */
    1331             :   void offset(dof_id_signed_type d0, dof_id_signed_type d1, dof_id_signed_type d2)
    1332             :   {
    1333             :     ArrayBase<T, 3>::offset({d0, d1, d2});
    1334             :   }
    1335             : 
    1336             :   /**
    1337             :    * Get an array entry
    1338             :    * @param i0 The first dimension index
    1339             :    * @param i1 The second dimension index
    1340             :    * @param i2 The third dimension index
    1341             :    * @returns The reference of the entry depending on the architecture this function is being
    1342             :    * called on
    1343             :    */
    1344             :   KOKKOS_FUNCTION T &
    1345   138366298 :   operator()(dof_id_signed_type i0, dof_id_signed_type i1, dof_id_signed_type i2) const
    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   138366298 :     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>
    1357             : class Array<T, 4> : public ArrayBase<T, 4>
    1358             : {
    1359             : #ifdef MOOSE_KOKKOS_SCOPE
    1360             :   usingKokkosArrayBaseMembers(T, 4);
    1361             : #endif
    1362             : 
    1363             : public:
    1364             :   /**
    1365             :    * Default constructor
    1366             :    */
    1367           0 :   Array() = default;
    1368             :   /**
    1369             :    * Copy constructor
    1370             :    */
    1371             :   Array(const Array<T, 4> & array) : ArrayBase<T, 4>(array) {}
    1372             :   /**
    1373             :    * Shallow copy another Kokkos array
    1374             :    * @param array The Kokkos array to be shallow copied
    1375             :    */
    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             :   /**
    1385             :    * Constructor
    1386             :    * Initialize and allocate array with given dimensions
    1387             :    * This allocates both host and device data
    1388             :    * @param n0 The first dimension size
    1389             :    * @param n1 The second dimension size
    1390             :    * @param n2 The third dimension size
    1391             :    * @param n3 The fourth dimension size
    1392             :    */
    1393             :   Array(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3) { create(n0, n1, n2, n3); }
    1394             : 
    1395             :   /**
    1396             :    * Initialize array with given dimensions but do not allocate
    1397             :    * @param n0 The first dimension size
    1398             :    * @param n1 The second dimension size
    1399             :    * @param n2 The third dimension size
    1400             :    * @param n3 The fourth dimension size
    1401             :    */
    1402             :   void init(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
    1403             :   {
    1404             :     this->template createInternal<false, false>({n0, n1, n2, n3});
    1405             :   }
    1406             :   /**
    1407             :    * Initialize and allocate array with given dimensions on host and device
    1408             :    * @param n0 The first dimension size
    1409             :    * @param n1 The second dimension size
    1410             :    * @param n2 The third dimension size
    1411             :    * @param n3 The fourth dimension size
    1412             :    */
    1413             :   void create(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
    1414             :   {
    1415             :     this->template createInternal<true, true>({n0, n1, n2, n3});
    1416             :   }
    1417             :   /**
    1418             :    * Initialize and allocate array with given dimensions on host only
    1419             :    * @param n0 The first dimension size
    1420             :    * @param n1 The second dimension size
    1421             :    * @param n2 The third dimension size
    1422             :    * @param n3 The fourth dimension size
    1423             :    */
    1424             :   void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
    1425             :   {
    1426             :     this->template createInternal<true, false>({n0, n1, n2, n3});
    1427             :   }
    1428             :   /**
    1429             :    * Initialize and allocate array with given dimensions on device only
    1430             :    * @param n0 The first dimension size
    1431             :    * @param n1 The second dimension size
    1432             :    * @param n2 The third dimension size
    1433             :    * @param n3 The fourth dimension size
    1434             :    */
    1435             :   void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3)
    1436             :   {
    1437             :     this->template createInternal<false, true>({n0, n1, n2, n3});
    1438             :   }
    1439             :   /**
    1440             :    * Set starting index offsets
    1441             :    * @param d0 The first dimension offset
    1442             :    * @param d1 The second dimension offset
    1443             :    * @param d2 The third dimension offset
    1444             :    * @param d3 The fourth dimension offset
    1445             :    */
    1446             :   void
    1447             :   offset(dof_id_signed_type d0, dof_id_signed_type d1, dof_id_signed_type d2, dof_id_signed_type d3)
    1448             :   {
    1449             :     ArrayBase<T, 4>::offset({d0, d1, d2, d3});
    1450             :   }
    1451             : 
    1452             :   /**
    1453             :    * Get an array entry
    1454             :    * @param i0 The first dimension index
    1455             :    * @param i1 The second dimension index
    1456             :    * @param i2 The third dimension index
    1457             :    * @param i3 The fourth dimension index
    1458             :    * @returns The reference of the entry depending on the architecture this function is being called
    1459             :    * on
    1460             :    */
    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>
    1478             : class Array<T, 5> : public ArrayBase<T, 5>
    1479             : {
    1480             : #ifdef MOOSE_KOKKOS_SCOPE
    1481             :   usingKokkosArrayBaseMembers(T, 5);
    1482             : #endif
    1483             : 
    1484             : public:
    1485             :   /**
    1486             :    * Default constructor
    1487             :    */
    1488           0 :   Array() = default;
    1489             :   /**
    1490             :    * Copy constructor
    1491             :    */
    1492             :   Array(const Array<T, 5> & array) : ArrayBase<T, 5>(array) {}
    1493             :   /**
    1494             :    * Shallow copy another Kokkos array
    1495             :    * @param array The Kokkos array to be shallow copied
    1496             :    */
    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             :   /**
    1506             :    * Constructor
    1507             :    * Initialize and allocate array with given dimensions
    1508             :    * This allocates both host and device data
    1509             :    * @param n0 The first dimension size
    1510             :    * @param n1 The second dimension size
    1511             :    * @param n2 The third dimension size
    1512             :    * @param n3 The fourth dimension size
    1513             :    * @param n4 The fifth dimension size
    1514             :    */
    1515             :   Array(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
    1516             :   {
    1517             :     create(n0, n1, n2, n3, n4);
    1518             :   }
    1519             : 
    1520             :   /**
    1521             :    * Initialize array with given dimensions but do not allocate
    1522             :    * @param n0 The first dimension size
    1523             :    * @param n1 The second dimension size
    1524             :    * @param n2 The third dimension size
    1525             :    * @param n3 The fourth dimension size
    1526             :    * @param n4 The fifth dimension size
    1527             :    */
    1528             :   void init(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
    1529             :   {
    1530             :     this->template createInternal<false, false>({n0, n1, n2, n3, n4});
    1531             :   }
    1532             :   /**
    1533             :    * Initialize and allocate array with given dimensions on host and device
    1534             :    * @param n0 The first dimension size
    1535             :    * @param n1 The second dimension size
    1536             :    * @param n2 The third dimension size
    1537             :    * @param n3 The fourth dimension size
    1538             :    * @param n4 The fifth dimension size
    1539             :    */
    1540             :   void create(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
    1541             :   {
    1542             :     this->template createInternal<true, true>({n0, n1, n2, n3, n4});
    1543             :   }
    1544             :   /**
    1545             :    * Initialize and allocate array with given dimensions on host only
    1546             :    * @param n0 The first dimension size
    1547             :    * @param n1 The second dimension size
    1548             :    * @param n2 The third dimension size
    1549             :    * @param n3 The fourth dimension size
    1550             :    * @param n4 The fifth dimension size
    1551             :    */
    1552             :   void createHost(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
    1553             :   {
    1554             :     this->template createInternal<true, false>({n0, n1, n2, n3, n4});
    1555             :   }
    1556             :   /**
    1557             :    * Initialize and allocate array with given dimensions on device only
    1558             :    * @param n0 The first dimension size
    1559             :    * @param n1 The second dimension size
    1560             :    * @param n2 The third dimension size
    1561             :    * @param n3 The fourth dimension size
    1562             :    * @param n4 The fifth dimension size
    1563             :    */
    1564             :   void createDevice(dof_id_type n0, dof_id_type n1, dof_id_type n2, dof_id_type n3, dof_id_type n4)
    1565             :   {
    1566             :     this->template createInternal<false, true>({n0, n1, n2, n3, n4});
    1567             :   }
    1568             :   /**
    1569             :    * Set starting index offsets
    1570             :    * @param d0 The first dimension offset
    1571             :    * @param d1 The second dimension offset
    1572             :    * @param d2 The third dimension offset
    1573             :    * @param d3 The fourth dimension offset
    1574             :    * @param d4 The fifth dimension offset
    1575             :    */
    1576             :   void offset(dof_id_signed_type d0,
    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             : 
    1585             :   /**
    1586             :    * Get an array entry
    1587             :    * @param i0 The first dimension index
    1588             :    * @param i1 The second dimension index
    1589             :    * @param i2 The third dimension index
    1590             :    * @param i3 The fourth dimension index
    1591             :    * @param i4 The fifth dimension index
    1592             :    * @returns The reference of the entry depending on the architecture this function is being called
    1593             :    * on
    1594             :    */
    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             : };
    1612             : ///@}
    1613             : 
    1614             : template <typename T>
    1615             : using Array1D = Array<T, 1>;
    1616             : template <typename T>
    1617             : using Array2D = Array<T, 2>;
    1618             : template <typename T>
    1619             : using Array3D = Array<T, 3>;
    1620             : template <typename T>
    1621             : using Array4D = Array<T, 4>;
    1622             : template <typename T>
    1623             : using Array5D = Array<T, 5>;
    1624             : 
    1625             : } // namespace Kokkos
    1626             : } // namespace Moose

Generated by: LCOV version 1.14