   ! ================================================================================
   ! Update k-mode index
   !
   ! The k-mode index is a (l,m,n) triplets
   !
   ! Assumes kmode start is (kmax_x, kmax_y, kmax_z)
   ! l ranges from 0 to kmax_x
   ! m ranges from -kmax_y to +kmax_y, except when l==0, it ranges from 1 to +kmax_x
   ! n ranges from -kmax_z to +kmax_z
   subroutine update_kmode_index(this, l, m, n)
      implicit none
      ! Parameters
      ! ----------
      type(MW_ewald_t), intent(in) :: this
      integer, intent(inout) :: l
      integer, intent(inout) :: m
      integer, intent(inout) :: n

      ! Local
      ! ----
      n = n + 1
      if (n > this%kmax_z) then
         n = -this%kmax_z
         m = m + 1
         if (m > this%kmax_y) then
            m = -this%kmax_y
            l = l + 1
         end if
      end if

   end subroutine update_kmode_index

   ! ================================================================================
   ! compute k-mode index
   !
   ! The k-mode index is a (l,m,n) triplets
   subroutine compute_kmode_index(num_pbc, kmax_x, kmax_y, kmax_z, imode, l, m, n)
      implicit none
      !$acc routine seq
      ! Parameters
      ! ----------
      integer, intent(in) :: num_pbc
      integer, intent(in) :: kmax_x, kmax_y, kmax_z
      integer, intent(in) :: imode
      integer, intent(out) :: l
      integer, intent(out) :: m
      integer, intent(out) :: n

      if (num_pbc == 3) then
         call compute_kmode_index_3DPBC(kmax_x, kmax_y, kmax_z, imode, l, m, n)
      else if (num_pbc == 2) then
         call compute_kmode_index_2DPBC(kmax_x, kmax_y, kmax_z, imode, l, m, n)
      end if
   end subroutine compute_kmode_index

   ! ================================================================================
   ! compute k-mode index
   !
   ! The k-mode index is a (l,m,n) triplets
   !
   ! Assumes kmode start is (kmax_x, kmax_y, kmax_z)
   ! l ranges from 0 to kmax_x
   ! m ranges from -kmax_y to +kmax_y, except when l==0, it ranges from 1 to +kmax_y
   ! n ranges from -kmax_z to +kmax_z
   !
   ! imode is the global mode index: imode=1 => k=0, l=1, n=-kmax_z
   !
   !    n = modulo((imode-1), 2*kmax_z+1) - kmax_z
   ! if imode in [ 1; kmax_y*(2*kmax_z+1) ] then
   !    imode = (n+kmax_z) + (m-1) * (2*kmax_z+1) + 1
   !    n = modulo((imode-1), 2*kmax_z+1) - kmax_z
   !    m = (imode-1) / (2*kmax_z+1) +1
   !    l = 0
   ! else ! imode > kmax_y*(2*kmax_z+1)
   !    imode - kmax_y*(2*kmax_z+1) = (n+kmax_z) + (m+kmax_y)*(2*kmax_z+1) + (l-1)*(2*kmax_z+1)*(2*kmax_y+1) + 1
   !    n = modulo(imode - kmax_y*(2*kmax_z+1) - 1, (2*kmax_z+1)) - kmax_z
   !    m = modulo((imode - kmax_y*(2*kmax_z+1) - (n+kmax_z) - 1) / (2*kmax_z+1), (2*kmax_y+1)) - kmax_y
   !    l = (imode - kmax_y*(2*kmax_z+1) - (n+kmax_z) - 1) / (2*kmax_z+1)*(2*kmax_y+1) + 1
   !
   subroutine compute_kmode_index_2DPBC(kmax_x, kmax_y, kmax_z, imode, l, m, n)
      implicit none
      !$acc routine seq
      ! Parameters
      ! ----------
      integer, intent(in) :: kmax_x, kmax_y, kmax_z
      integer, intent(in) :: imode
      integer, intent(out) :: l
      integer, intent(out) :: m
      integer, intent(out) :: n

      ! Local
      ! ----
      integer :: imode_mn

      if (imode <= kmax_y*(2*kmax_z+1)) then
         n = mod((imode - 1), (2*kmax_z+1)) - kmax_z
         m = (imode - 1) / (2*kmax_z+1) + 1 ! integer division
         l = 0
      else
         n = mod((imode - 1), (2*kmax_z+1)) - kmax_z
         imode_mn = (imode - kmax_y*(2*kmax_z+1) - (n + kmax_z) - 1) / (2*kmax_z + 1) ! integer division
         m = mod(imode_mn, (2*kmax_y+1)) - kmax_y
         l = imode_mn / (2*kmax_y+1) + 1 ! integer division
      end if
   end subroutine compute_kmode_index_2DPBC

   ! ================================================================================
   ! compute k-mode index for 3D PBC
   !
   ! The k-mode index is a (l,m,n) triplets
   !
   ! Assumes kmode start is (kmax_x, kmax_y, kmax_z)
   ! l ranges from 0 to kmax_x
   ! m ranges from -kmax_y to +kmax_y, except when l==0, it ranges from 1 to +kmax_y
   ! n ranges from -kmax_z to +kmax_z, except when l==0 and m==0, it ranges from 1 to +kmax_z
   !
   ! imode is the global mode index: imode=1 => k=0, l=0, n=1
   !
   !    n = modulo((imode-1), 2*kmax_z+1) - kmax_z
   ! if imode in [ 1; kmax_y*(2*kmax_z+1) ] then
   !    imode = (n+kmax_z) + (m-1) * (2*kmax_z+1) + 1
   !    n = modulo((imode-1), 2*kmax_z+1) - kmax_z
   !    m = (imode-1) / (2*kmax_z+1) +1
   !    l = 0
   ! else ! imode > kmax_y*(2*kmax_z+1)
   !    imode - kmax_y*(2*kmax_z+1) = (n+kmax_z) + (m+kmax_y)*(2*kmax_z+1) + (l-1)*(2*kmax_z+1)*(2*kmax_y+1) + 1
   !    n = modulo(imode - kmax_y*(2*kmax_z+1) - 1, (2*kmax_z+1)) - kmax_z
   !    m = modulo((imode - kmax_y*(2*kmax_z+1) - (n+kmax_z) - 1) / (2*kmax_z+1), (2*kmax_y+1)) - kmax_y
   !    l = (imode - kmax_y*(2*kmax_z+1) - (n+kmax_z) - 1) / (2*kmax_z+1)*(2*kmax_y+1) + 1
   !
   subroutine compute_kmode_index_3DPBC(kmax_x, kmax_y, kmax_z, imode, l, m, n)
      implicit none
      !$acc routine seq
      ! Parameters
      ! ----------
      integer, intent(in) :: kmax_x, kmax_y, kmax_z
      integer, intent(in) :: imode
      integer, intent(out) :: l
      integer, intent(out) :: m
      integer, intent(out) :: n

      ! Local
      ! ----
      integer :: imode_mn

      if (imode <= kmax_z) then
         n = imode
         m = 0
         l = 0
      else if (imode <= kmax_z + kmax_y*(2*kmax_z+1)) then
         n = mod((imode - kmax_z - 1), (2*kmax_z+1)) - kmax_z
         m = (imode - kmax_z - 1) / (2*kmax_z+1) + 1 ! integer division
         l = 0
      else
         n = mod((imode - kmax_z - 1), (2*kmax_z+1)) - kmax_z
         imode_mn = (imode - kmax_z - kmax_y*(2*kmax_z+1) - (n + kmax_z) - 1) / (2*kmax_z + 1) ! integer division
         m = mod(imode_mn, (2*kmax_y+1)) - kmax_y
         l = imode_mn / (2*kmax_y+1) + 1 ! integer division
      end if
   end subroutine compute_kmode_index_3DPBC

   ! ================================================================================
   ! Update k-mode index
   !
   ! The k-mode index is a (l,m,n) triplets
   ! During ewald summation, we want to add small values first to avoid rounding
   ! errors
   !
   ! Assumes kmode start is (kmax_x, kmax_y, kmax_z)
   ! l ranges from 0 to kmax_x
   ! m ranges from -kmax_y to +kmax_y, except when l==0, it ranges from 1 to +kmax_x
   ! n ranges from -kmax_z to +kmax_z
   subroutine update_kmode_index_2(this, l, m, n)
      implicit none
      ! Parameters
      ! ----------
      type(MW_ewald_t), intent(in) :: this
      integer, intent(inout) :: l
      integer, intent(inout) :: m
      integer, intent(inout) :: n

      ! Local
      ! ----
      integer :: s
      integer :: l_next, m_next, n_next

      ! Compute sum of mode index
      s = abs(l) + abs(n) + abs(m)

      if (l > 0) then
         if (m > 0) then
            if (n > 0) then
               ! (l>0) .and. (m>0) .and. (n>0)
               l_next = l
               m_next = m
               n_next = -n
            else
               ! (l>0) .and. (m>0) .and. (n<=0)
               l_next = l
               m_next = -m
               n_next = -n
            end if
         else if (m < 0) then
            if (n > 0) then
               ! (l>0) .and. (m<0) .and. (n>0)
               l_next = l
               m_next = m
               n_next = -n
            else if (n == -this%kmax_z) then
               if (m == -this%kmax_y) then
                  ! (l>0) .and. (m==-this%kmax_y) .and. (n==-this%kmax_z)
                  l_next = min((s-1), this%kmax_x)
                  m_next = min((s-1) - (l_next), this%kmax_y)
                  n_next = min((s-1) - (l_next+m_next), this%kmax_z)
               else
                  ! (l>0) .and. (-this%kmax_y<m<0) .and. (n==-this%kmax_z)
                  l_next = l-1
                  m_next = min(s - (l_next), this%kmax_y)
                  n_next = min(s - (l_next+m_next), this%kmax_z)
               end if
            else
               ! (l>0) .and. (m<0) .and. (-this%kmax_z<n<=0)
               l_next = l
               m_next = -m - 1
               n_next = -n + 1
            end if
         else
            if (n > 0) then
               ! (l>0) .and. (m==0) .and. (n>0)
               l_next = l
               m_next = m
               n_next = -n
            else
               ! (l>0) .and. (m==0) .and. (n<=0)
               l_next = l-1
               m_next = min(s - (l_next), this%kmax_y)
               n_next = min(s - (l_next+m_next), this%kmax_z)
            end if
         end if
      else
         if (m > 1) then
            if (n > 0) then
               ! (l==0) .and. (m>1) .and. (n>0)
               l_next = l
               m_next = m
               n_next = -n
            else
               if (n == -this%kmax_z) then
                  ! (l==0) .and. (m>1) .and. (n==-this%kmax_z)
                  l_next = min((s-1), this%kmax_x)
                  m_next = min((s-1) - (l_next), this%kmax_y)
                  n_next = min((s-1) - (l_next+m_next), this%kmax_z)
               else
                  ! (l==0) .and. (m>1) .and. (-this%kmax_z<n<=0)
                  l_next = l
                  m_next = m - 1
                  n_next = min(s - (l_next+m_next), this%kmax_z)
               end if
            end if
         else
            if (n > 0) then
               ! (l==0) .and. (m==1) .and. (n>0)
               l_next = l
               m_next = m
               n_next = -n
            else
               ! (l==0) .and. (m=1) .and. (n<=0)
               l_next = min((s-1), this%kmax_x)
               m_next = min((s-1) - (l_next), this%kmax_y)
               n_next = min((s-1) - (l_next+m_next), this%kmax_z)
            end if
         end if
      end if

      ! update values
      l = l_next
      m = m_next
      n = n_next

   end subroutine update_kmode_index_2
