module MW_multipole_tensors
   use MW_kinds, only: wp 
   implicit none 
   private

   ! Public functions
   ! ----------------------
   public :: tij
   public :: tij_a
   public :: tij_ab
   public :: tij_abc

contains 

! ===============================================================================================
! Compute the modified multipolar tensors of rank 0 (scalar).
subroutine tij(drnorm2, dx, dy, dz, alpha, alphasq, alphapi, t)
   implicit none

   ! Passed in
   ! ---------
   real(wp), intent(in) :: drnorm2
   real(wp), intent(in) :: dx,dy,dz
   real(wp), intent(in) :: alpha
   real(wp), intent(in) :: alphasq ! alpha*alpha
   real(wp), intent(in) :: alphapi ! 2.0_wp*alpha/sqrtpi

   ! Result
   ! ------
   real(wp), intent(inout) :: t

   ! Local
   ! -----
   real(wp) :: drnorm

   drnorm = sqrt(drnorm2)
   t = erfc(alpha*drnorm)/drnorm

end subroutine tij

! ===============================================================================================
! Compute the modified multipolar tensors of rank 1 (dimension 1x3).
subroutine tij_a(drnorm2, dx, dy, dz, alpha, alphasq, alphapi, tij) 
   implicit none

   ! Passed in
   ! ---------
   real(wp), intent(in) :: drnorm2
   real(wp), intent(in) :: dx,dy,dz
   real(wp), intent(in) :: alpha
   real(wp), intent(in) :: alphasq ! alpha*alpha
   real(wp), intent(in) :: alphapi ! 2.0_wp*alpha/sqrtpi

   ! Result
   ! ----------
   real(wp), dimension(3), intent(inout) :: tij

   ! Local
   ! ----------
   real(wp), dimension(3) :: dr ! dr = dri - drj
   real(wp) :: drnorm, drnormrec, drnorm2rec
   real(wp) :: erfc_alpha, exp_alpha
   real(wp) :: drnorm3rec_scr

   dr(1) = -dx ! dx = dxj - dxi
   dr(2) = -dy ! dy = dyj - dyi
   dr(3) = -dz ! dz = dzj - dzi

   drnorm = sqrt(drnorm2)
   drnormrec = 1.0_wp/drnorm
   drnorm2rec = drnormrec*drnormrec
   erfc_alpha = erfc(alpha*drnorm)*drnormrec
   exp_alpha = exp(-alphasq*drnorm2)*alphapi

   drnorm3rec_scr = (erfc_alpha + exp_alpha)*drnorm2rec

   tij = -dr*drnorm3rec_scr
   
end subroutine tij_a

! ===============================================================================================
! Compute the modified multipolar tensors of rank 2 (6 independent components).
subroutine tij_ab(drnorm2, dx, dy, dz, alpha, alphasq, alphapi, tij)
   implicit none

   ! Passed in
   ! ---------
   real(wp), intent(in) :: drnorm2
   real(wp), intent(in) :: dx,dy,dz
   real(wp), intent(in) :: alpha
   real(wp), intent(in) :: alphasq ! alpha*alpha
   real(wp), intent(in) :: alphapi ! 2.0_wp*alpha/sqrtpi

   ! Result
   ! ----------
   real(wp), dimension(3,3), intent(inout) :: tij ! six independent components

   ! Local
   ! ----------
   real(wp), dimension(3) :: dr ! dr = dri - drj
   integer :: a, b
   real(wp) :: drnorm, drnormrec, drnorm2rec
   real(wp) :: erfc_alpha, exp_alpha
   real(wp) :: drnorm3rec_scr, drnorm5rec_scr

   dr(1) = -dx ! dx = dxj - dxi
   dr(2) = -dy ! dy = dyj - dyi
   dr(3) = -dz ! dz = dzj - dzi

   drnorm = sqrt(drnorm2)
   drnormrec = 1.0_wp/drnorm
   drnorm2rec = drnormrec*drnormrec
   erfc_alpha = erfc(alpha*drnorm)*drnormrec
   exp_alpha = exp(-alphasq*drnorm2)*alphapi

   drnorm3rec_scr = (erfc_alpha + exp_alpha)*drnorm2rec
   drnorm5rec_scr = (drnorm3rec_scr + 2.0_wp*alphasq*exp_alpha/3.0_wp)*drnorm2rec

   do b = 1, 3
      do a = 1, 3
         tij(a, b) = 3.0_wp*dr(a)*dr(b)*drnorm5rec_scr 
         if (a == b) tij(a, b) = tij(a, b) - drnorm3rec_scr
      end do
   end do
   
end subroutine tij_ab

! ===============================================================================================
! Compute the modified multipolar tensors of rank 3 (10 independent components).
subroutine tij_abc(drnorm2, dx, dy, dz, alpha, alphasq, alphapi, tij)
   implicit none

   ! Passed in
   ! ---------
   real(wp), intent(in) :: drnorm2
   real(wp), intent(in) :: dx,dy,dz
   real(wp), intent(in) :: alpha
   real(wp), intent(in) :: alphasq ! alpha*alpha
   real(wp), intent(in) :: alphapi ! 2.0_wp*alpha/sqrtpi

   ! Result
   ! ----------
   real(wp), dimension(3,3,3), intent(inout) :: tij ! 10 independent components

   ! Local
   ! ----------
   real(wp), dimension(3) :: dr ! dr = dri - drj
   integer :: a, b, c
   real(wp) :: drnorm, drnormrec, drnorm2rec
   real(wp) :: erfc_alpha, exp_alpha, tmp
   real(wp) :: drnorm3rec_scr, drnorm5rec_scr, drnorm7rec_scr

   dr(1) = -dx ! dx = dxj - dxi
   dr(2) = -dy ! dy = dyj - dyi
   dr(3) = -dz ! dz = dzj - dzi

   drnorm = sqrt(drnorm2)
   drnormrec = 1.0_wp/drnorm
   drnorm2rec = drnormrec*drnormrec
   erfc_alpha = erfc(alpha*drnorm)*drnormrec
   exp_alpha = exp(-alphasq*drnorm2)*alphapi

   drnorm3rec_scr = (erfc_alpha + exp_alpha)*drnorm2rec
   drnorm5rec_scr = (drnorm3rec_scr + 2.0_wp*alphasq*exp_alpha/3.0_wp)*drnorm2rec
   drnorm7rec_scr = (drnorm5rec_scr + 4.0_wp*alphasq*alphasq*exp_alpha/15.0_wp)*drnorm2rec

   do c = 1, 3
      do b = 1, 3
         do a = 1, 3
            tij(a, b, c) = -15.0_wp*dr(a)*dr(b)*dr(c)*drnorm7rec_scr
            tmp = 3.0_wp*drnorm5rec_scr
            if (a == b) tij(a, b, c) = tij(a, b, c) + tmp*dr(c)
            if (a == c) tij(a, b, c) = tij(a, b, c) + tmp*dr(b)
            if (b == c) tij(a, b, c) = tij(a, b, c) + tmp*dr(a)
         end do
      end do
   end do

end subroutine tij_abc

end module MW_multipole_tensors