tetrahedron.F90 Source File


This file depends on

sourcefile~~tetrahedron.f90~~EfferentGraph sourcefile~tetrahedron.f90 tetrahedron.F90 sourcefile~constants.f90 constants.F90 sourcefile~tetrahedron.f90->sourcefile~constants.f90 sourcefile~utility.f90 utility.F90 sourcefile~tetrahedron.f90->sourcefile~utility.f90 sourcefile~utility.f90->sourcefile~constants.f90 sourcefile~comms.f90 comms.F90 sourcefile~utility.f90->sourcefile~comms.f90 sourcefile~error.f90 error.F90 sourcefile~utility.f90->sourcefile~error.f90 sourcefile~comms.f90->sourcefile~constants.f90 sourcefile~error_base.f90 error_base.F90 sourcefile~comms.f90->sourcefile~error_base.f90 sourcefile~error.f90->sourcefile~comms.f90 sourcefile~error.f90->sourcefile~error_base.f90

Files dependent on this one

sourcefile~~tetrahedron.f90~~AfferentGraph sourcefile~tetrahedron.f90 tetrahedron.F90 sourcefile~berry.f90 berry.F90 sourcefile~berry.f90->sourcefile~tetrahedron.f90 sourcefile~gyrotropic.f90 gyrotropic.F90 sourcefile~gyrotropic.f90->sourcefile~berry.f90 sourcefile~kpath.f90 kpath.F90 sourcefile~kpath.f90->sourcefile~berry.f90 sourcefile~kslice.f90 kslice.F90 sourcefile~kslice.f90->sourcefile~berry.f90 sourcefile~postw90.f90 postw90.F90 sourcefile~postw90.f90->sourcefile~berry.f90 sourcefile~postw90.f90->sourcefile~gyrotropic.f90 sourcefile~postw90.f90->sourcefile~kpath.f90 sourcefile~postw90.f90->sourcefile~kslice.f90

Source Code

!-*- mode: F90 -*-!
!------------------------------------------------------------!
! This file is distributed as part of the Wannier90 code and !
! under the terms of the GNU General Public License. See the !
! file `LICENSE' in the root directory of the Wannier90      !
! distribution, or http://www.gnu.org/copyleft/gpl.txt       !
!                                                            !
! The webpage of the Wannier90 code is www.wannier.org       !
!                                                            !
! The Wannier90 code is hosted on GitHub:                    !
!                                                            !
! https://github.com/wannier-developers/wannier90            !
!------------------------------------------------------------!
!                                                            !
!  w90_tetrahedron: functions for tetrahedron method         !
!                                                            !
!------------------------------------------------------------!

module w90_tetrahedron

  use w90_constants, only: dp

  implicit none

  private
  !tetrahedron_fermidirac
  !tetrahedron_sort
  !tetrahedron_jacobian
  !tetrahedron_log1p

  public :: tetrahedron_spinhall ! Minsu Ghim, and Cheol-Hwan Park, PRB 106 075126
  ! To do: extend to other quantities(anomalous, ...)
  public :: tetrahedron_integral
  public :: tetrahedron_P_matrix_init
  public :: tetrahedron_array_init
  public :: tetrahedron_array_small_init

contains

  subroutine tetrahedron_P_matrix_init(P_matrix)

    use w90_constants, only: dp

    implicit none

    real(kind=dp), dimension(4, 20), intent(inout) :: P_matrix

    ! correction, Kawamura PRB 89 094515
    P_matrix(1, 1:4) = real((/1440, 0, 30, 0/), dp)
    P_matrix(2, 1:4) = real((/0, 1440, 0, 30/), dp)
    P_matrix(3, 1:4) = real((/30, 0, 1440, 0/), dp)
    P_matrix(4, 1:4) = real((/0, 30, 0, 1440/), dp)
    !
    P_matrix(1, 5:8) = real((/-38, 7, 17, -28/), dp)
    P_matrix(2, 5:8) = real((/-28, -38, 7, 17/), dp)
    P_matrix(3, 5:8) = real((/17, -28, -38, 7/), dp)
    P_matrix(4, 5:8) = real((/7, 17, -28, -38/), dp)
    !
    P_matrix(1, 9:12) = real((/-56, 9, -46, 9/), dp)
    P_matrix(2, 9:12) = real((/9, -56, 9, -46/), dp)
    P_matrix(3, 9:12) = real((/-46, 9, -56, 9/), dp)
    P_matrix(4, 9:12) = real((/9, -46, 9, -56/), dp)
    !
    P_matrix(1, 13:16) = real((/-38, -28, 17, 7/), dp)
    P_matrix(2, 13:16) = real((/7, -38, -28, 17/), dp)
    P_matrix(3, 13:16) = real((/17, 7, -38, -28/), dp)
    P_matrix(4, 13:16) = real((/-28, 17, 7, -38/), dp)
    !
    P_matrix(1, 17:20) = real((/-18, -18, 12, -18/), dp)
    P_matrix(2, 17:20) = real((/-18, -18, -18, 12/), dp)
    P_matrix(3, 17:20) = real((/12, -18, -18, -18/), dp)
    P_matrix(4, 17:20) = real((/-18, 12, -18, -18/), dp)
    !
    P_matrix(1:4, 1:20) = P_matrix(1:4, 1:20)/1260.0_dp

  end subroutine tetrahedron_P_matrix_init

  subroutine tetrahedron_array_small_init(tet_array_small)

    implicit none

    integer, dimension(6, 4), intent(inout) :: tet_array_small

    ! without correction
    !                                               z                     !
    !                                                 7----------8        ! tetrahedron #1: 1-5-6-8
    tet_array_small(1, :) = (/1, 5, 6, 8/)  !        /|         /| layer 2! tetrahedron #2: 1-7-5-8
    tet_array_small(2, :) = (/1, 7, 5, 8/)  !       5----------6 |        ! tetrahedron #3: 1-3-7-8
    tet_array_small(3, :) = (/1, 3, 7, 8/)  !       | | y      | |        ! tetrahedron #4: 1-4-3-8
    tet_array_small(4, :) = (/1, 4, 3, 8/)  !       | 3--------|-4        ! tetrahedron #5: 1-2-4-8
    tet_array_small(5, :) = (/1, 2, 4, 8/)  !       |/         |/  layer 1! tetrahedron #6: 1-6-2-8
    tet_array_small(6, :) = (/1, 6, 2, 8/)  !       1----------2 x        !
    ! 1-8 : main diagonal         !
    !=============================!

  end subroutine tetrahedron_array_small_init

  subroutine tetrahedron_array_init(tet_array)

    implicit none

    integer, dimension(6, 20), intent(inout) :: tet_array
    ! with correction, Kawamura PRB 89 094515
    !                                               z                     !
    !                                       !         61--62--63-64       ! tetrahedron #1: 22-38-39-43
    tet_array(1, 1:4) = (/22, 38, 39, 43/)  !        /|         /| layer 4! tetrahedron #2: 22-42-38-43
    tet_array(2, 1:4) = (/22, 42, 38, 43/)  !       49--50--51-52|        ! tetrahedron #3: 22-26-42-43
    tet_array(3, 1:4) = (/22, 26, 42, 43/)  !       | | y      | |        ! tetrahedron #4: 22-27-26-43
    tet_array(4, 1:4) = (/22, 27, 26, 43/)  !       | 13--14--1|-16       ! tetrahedron #5: 22-23-27-43
    tet_array(5, 1:4) = (/22, 23, 27, 43/)  !       |/         |/  layer 1! tetrahedron #6: 22-39-23-43
    tet_array(6, 1:4) = (/22, 39, 23, 43/)  !       1---2---3--4 x        !
    ! 22-43 : main diagonal       !
    !=============================!
    tet_array(1, 5:20) = (/6, 37, 35, 64, 5, 33, 56, 48, 1, 54, 40, 47, 59, 23, 42, 18/)
    tet_array(2, 5:20) = (/2, 46, 33, 64, 6, 41, 54, 44, 1, 62, 34, 48, 63, 18, 47, 17/)
    tet_array(3, 5:20) = (/18, 10, 41, 64, 2, 9, 62, 60, 1, 30, 58, 44, 47, 38, 27, 21/)
    tet_array(4, 5:20) = (/17, 28, 9, 64, 18, 11, 30, 59, 1, 32, 25, 60, 48, 21, 44, 5/)
    tet_array(5, 5:20) = (/21, 19, 11, 64, 17, 3, 32, 63, 1, 24, 31, 59, 44, 26, 39, 6/)
    tet_array(6, 5:20) = (/5, 55, 3, 64, 21, 35, 24, 47, 1, 56, 7, 63, 60, 6, 59, 2/)
    !note: 18 points(4, 8, 12, 13, 14, 15, 16, 20, 29, 36, 45, 49, 50, 51, 52, 53, 57, 61) are not used

  end subroutine tetrahedron_array_init

  !================================================!
  function tetrahedron_spinhall(F, E1, E2, t, hw, Ef, type, tet_cutoff, avoid_deg)
    !=============================================================================
    ! Calculates contribution from a single tetrahedron, for the Kubo formula.   !
    ! "integral d3k (f_{nk} - f_{mk}) * (...)"
    ! Ref: Minsu Ghim and Cheol-Hwan Park, PRB 106 075126                        !
    !=============================================================================

    use w90_constants, only: dp

    implicit none

    real(kind=dp) :: tetrahedron_spinhall
    real(kind=dp), dimension(4), intent(in) :: F, E1, E2
    real(kind=dp), dimension(3, 3), intent(in) :: t
    real(kind=dp), intent(in) :: hw, Ef
    integer, intent(in) :: type
    real(kind=dp), intent(in) :: tet_cutoff
    real(kind=dp), intent(in) :: avoid_deg
    !intermediate variables, s:sorted
    real(kind=dp) :: t_s(3, 3), t_small(3, 3), x(3), y
    real(kind=dp), dimension(4) :: D, occ1, occ2, F_s, E1_s, E2_s, &
                                   F_small, D_small
    integer       :: i
    logical       :: flag1, flag2

    !fnk-fmk = 0 then quickly returns zero
    occ1 = 0.0_dp; occ2 = 0.0_dp; flag1 = .true.; flag2 = .true.
    do i = 1, 4
      if (E1(i) < Ef) occ1(i) = 1.0_dp
      if (E2(i) < Ef) occ2(i) = 1.0_dp
      if (occ1(i) /= 1.0 .or. occ2(i) /= 1.0) flag1 = flag1 .and. .false.
      if (occ1(i) /= 0.0 .or. occ2(i) /= 0.0) flag2 = flag2 .and. .false.
    end do
    if (flag1 .or. flag2) then
      tetrahedron_spinhall = 0.0_dp
    else
      tetrahedron_spinhall = tetrahedron_fermidirac(F, E1, E2, t, hw, Ef, type, tet_cutoff, avoid_deg) &
                             - tetrahedron_fermidirac(F, E2, E1, t, hw, Ef, type, tet_cutoff, avoid_deg)
    end if

    return

  end function tetrahedron_spinhall

  function tetrahedron_fermidirac(F, E_ref, E2, t, hw, Ef, type, tet_cutoff, avoid_deg)
    !=============================================================================
    ! Calculates contribution from a single tetrahedron, for the Kubo formula.   !
    ! "integral d3k f_{nk} * (...)
    !=============================================================================

    use w90_constants, only: dp

    implicit none

    real(kind=dp) :: tetrahedron_fermidirac
    real(kind=dp), dimension(4), intent(in) :: F, E_ref, E2
    real(kind=dp), dimension(3, 3), intent(in) :: t
    real(kind=dp), intent(in) :: hw, Ef
    integer, intent(in) :: type
    real(kind=dp), intent(in) :: tet_cutoff
    real(kind=dp), intent(in) :: avoid_deg
    !intermediate variables, s:sorted
    real(kind=dp) :: t_s(3, 3), t_small(3, 3), x(3), y
    real(kind=dp), dimension(4) :: D, F_s, E1_s, E2_s, F_small, D_small
    !result
    real(kind=dp) :: Ans
    integer :: i

    Ans = 0.0_dp
    !sorting vertices according to E_ref
    F_s = F; E1_s = E_ref; E2_s = E2; t_s = t !_s: sorted
    call tetrahedron_sort(E1_s, E2_s, F_s, t_s)
    D = E1_s - E2_s
    !case 1,2,3,4,5
    if (Ef < E1_s(1)) then       ! case 1: zero
      Ans = Ans + 0.0_dp
    else if (Ef < E1_s(2)) then  ! case 2: a small tet.

      x(1) = (Ef - E1_s(1))/(E1_s(2) - E1_s(1))
      x(2) = (Ef - E1_s(1))/(E1_s(3) - E1_s(1))
      x(3) = (Ef - E1_s(1))/(E1_s(4) - E1_s(1))

      F_small(1) = F_s(1); D_small(1) = D(1)
      do i = 1, 3
        F_small(i + 1) = F_s(1) + (F_s(i + 1) - F_s(1))*x(i)
        D_small(i + 1) = D(1) + (D(i + 1) - D(1))*x(i)
        t_small(:, i) = t_s(:, i)*x(i)
      end do
      Ans = Ans + tetrahedron_integral(F_small, D_small, t_small, hw, type, tet_cutoff, avoid_deg)

    else if (Ef < E1_s(3)) then  ! case 3: two tet.'s with cases 2 and 4

      x(1) = (Ef - E1_s(4))/(E1_s(2) - E1_s(4))
      x(2) = (Ef - E1_s(1))/(E1_s(3) - E1_s(1))
      x(3) = (Ef - E1_s(1))/(E1_s(4) - E1_s(1))
      y = (Ef - E1_s(3))/(E1_s(2) - E1_s(3))

      F_small = F_s; D_small = D; t_small = t_s
      F_small(4) = F_s(1) + (F_s(4) - F_s(1))*x(3)
      D_small(4) = D(1) + (D(4) - D(1))*x(3)
      t_small(:, 3) = t_s(:, 3)*x(3)
      Ans = Ans + tetrahedron_integral(F_small, D_small, t_small, hw, type, tet_cutoff, avoid_deg)

      F_small(1) = F_s(1) + (F_s(3) - F_s(1))*x(2); F_small(2) = F_s(3) + (F_s(2) - F_s(3))*y
      D_small(1) = D(1) + (D(3) - D(1))*x(2); D_small(2) = D(3) + (D(2) - D(3))*y
      t_small(:, 1) = t_s(:, 1)*y + t_s(:, 2)*(1 - y - x(2))
      t_small(:, 2) = t_s(:, 2)*(1 - x(2))
      t_small(:, 3) = t_s(:, 3)*x(3) - t_s(:, 2)*x(2)
      Ans = Ans - tetrahedron_integral(F_small, D_small, t_small, hw, type, tet_cutoff, avoid_deg)

      F_small(1) = F_s(4) + (F_s(2) - F_s(4))*x(1)
      F_small(3) = F_small(2); F_small(2) = F_s(2)
      D_small(1) = D(4) + (D(2) - D(4))*x(1)
      D_small(3) = D_small(2); D_small(2) = D(2)
      t_small(:, 1) = (t_s(:, 1) - t_s(:, 3))*(1 - x(1))
      t_small(:, 2) = t_s(:, 1)*(y - x(1)) + t_s(:, 2)*(1 - y) + t_s(:, 3)*(x(1) - 1)
      t_small(:, 3) = -t_s(:, 1)*x(1) + t_s(:, 3)*(x(1) + x(3) - 1)
      Ans = Ans + tetrahedron_integral(F_small, D_small, t_small, hw, type, tet_cutoff, avoid_deg)

    else if (Ef < E1_s(4)) then  ! case 4: a large tet. - a small tet.

      x(1) = (Ef - E1_s(4))/(E1_s(2) - E1_s(4))
      x(2) = (Ef - E1_s(4))/(E1_s(3) - E1_s(4))
      x(3) = (Ef - E1_s(1))/(E1_s(4) - E1_s(1))

      F_small(1) = F_s(4); F_small(2) = F_s(1) + (F_s(4) - F_s(1))*x(3)
      F_small(3) = F_s(4) + (F_s(2) - F_s(4))*x(1)
      F_small(4) = F_s(4) + (F_s(3) - F_s(4))*x(2)
      D_small(1) = D(4); D_small(2) = D(1) + (D(4) - D(1))*x(3)
      D_small(3) = D(4) + (D(2) - D(4))*x(1)
      D_small(4) = D(4) + (D(3) - D(4))*x(2)
      t_small(:, 1) = -t_s(:, 3)*(1 - x(3))
      t_small(:, 2) = (t_s(:, 1) - t_s(:, 3))*x(1)
      t_small(:, 3) = (t_s(:, 2) - t_s(:, 3))*x(2)
      Ans = Ans + tetrahedron_integral(F_s, D, t_s, hw, type, tet_cutoff, avoid_deg) &
            - tetrahedron_integral(F_small, D_small, t_small, hw, type, tet_cutoff, avoid_deg)

    else                      ! case 5: a large tet.
      Ans = Ans + tetrahedron_integral(F_s, D, t_s, hw, type, tet_cutoff, avoid_deg)
    end if
    tetrahedron_fermidirac = Ans

  end function tetrahedron_fermidirac

  !=======================================================================
  function tetrahedron_integral(F_in, D_in, t_in, hw, type, tet_cutoff, avoid_deg)
    !=============================================================================
    ! Calculates contribution from a single tetrahedron, for the Kubo formula.   !
    ! To do: extend to complex numbers                                           !
    ! type 1: nondissipative, linear/linear                                      !
    ! type 2: dissipative                                                        !
    ! type 3: nondissipative, linear/(linear)**2                                 !
    !                                                                            !
    ! Ref: Minsu Ghim and Cheol-Hwan Park, PRB 106 075126                        !
    !=============================================================================

    use w90_constants, only: dp
    use w90_utility, only: utility_inv3

    implicit none

    real(kind=dp) :: tetrahedron_integral
    real(kind=dp), dimension(4), intent(in) :: F_in, D_in
    real(kind=dp), dimension(3, 3), intent(in) :: t_in
    real(kind=dp), intent(in) :: hw
    integer, intent(in) :: type
    real(kind=dp), intent(in) :: tet_cutoff
    !small parameter to avoid a problem of degenearcy
    real(kind=dp), intent(in) :: avoid_deg
    !result
    real(kind=dp) :: Ans, Det_t

    !intermediate variables
    integer :: i, j, k, l
    real(kind=dp) :: D(4), F(4), t(3, 3), DAV, D_small_prev, D_large_prev
    real(kind=dp) :: dd(3), ll(3), ff, bb(4), cc(4, 3)
    integer :: a, b, c
    REAL(kind=dp) :: t_inverse(3, 3), dummy(4)
    REAL(kind=dp) :: GradD, Jac, y
    REAL(kind=dp) :: x(3)
    REAL(kind=dp), DIMENSION(0:2) :: F_uv

    D = D_in; F = F_in; t = t_in
    call tetrahedron_sort(D, F, dummy, t)
    Ans = 0.0_dp

    !case 1 and 3: nondissipative part, case 2: dissipative part
    if (type == 1 .or. type == 3) then
      if (type == 3) then
        !treatment for accidental small band spliting(but degenerate actually) cases
        do j = 1, 4
          if (abs(D(j)) < avoid_deg) then
            D(j) = avoid_deg*(abs(D(j))/D(j))
            F = 0
          end if
        end do
      end if

      !cutoff treatment, hw == 0.0 for case 3
      DAV = (D(2) + D(3))/2.0_dp
      if (abs((D(2) - D(3))/(DAV + hw)) < tet_cutoff) then
        D_small_prev = D(2); D_large_prev = D(3)
        D(3) = DAV + 0.5_dp*abs(DAV + hw)*tet_cutoff
        D(2) = DAV - 0.5_dp*abs(DAV + hw)*tet_cutoff
        if (D(1) > D(2)) D(1) = D(1) + (D(2) - D_small_prev)
        if (D(3) > D(4)) D(4) = D(4) + (D(3) - D_large_prev)
      end if
      DAV = (D(1) + D(2))/2.0_dp
      if (abs((D(1) - D(2))/(DAV + hw)) < tet_cutoff) then
        if (D(2) > 0) then
          D(1) = D(2)*(2.0_dp - tet_cutoff)/(2.0_dp + tet_cutoff)
        else
          D(1) = D(2)*(2.0_dp + tet_cutoff)/(2.0_dp - tet_cutoff)
        end if
      end if
      DAV = (D(3) + D(4))/2.0_dp
      if (abs((D(3) - D(4))/(DAV + hw)) < tet_cutoff) then
        if (D(3) > 0) then
          D(4) = D(3)*(2.0_dp + tet_cutoff)/(2.0_dp - tet_cutoff)
        else
          D(4) = D(3)*(2.0_dp - tet_cutoff)/(2.0_dp + tet_cutoff)
        end if
      end if

      !intermediate variables for case 1 and 3
      do i = 1, 3
        dd(i) = (D(4) - D(i))/(D(i) + hw)
        ll(i) = tetrahedron_log1p(dd(i))
      end do
      ff = 1.0_dp

      !determinant factor from parametrisation(tetrahedron volume)
      Det_t = ABS(t(1, 1)*t(2, 2)*t(3, 3) + t(1, 2)*t(2, 3)*t(3, 1) + t(1, 3)*t(2, 1)*t(3, 2) &
                  - t(1, 1)*t(2, 3)*t(3, 2) - t(1, 3)*t(2, 2)*t(3, 1) - t(1, 2)*t(2, 1)*t(3, 3))
    end if

    select case (type)
    case (1)
      do i = 1, 3
        a = i
        b = mod(i, 3) + 1
        c = mod(i + 1, 3) + 1
        cc(a, a) = -(1.0_dp + dd(a))*(3.0_dp*dd(a)**2 - 2.0_dp*(dd(b) + dd(c))*dd(a) + dd(b)*dd(c)) &
                   *((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(b, a) = -dd(a)*(1.0_dp + dd(b))*(dd(c) - dd(a))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(c, a) = dd(a)*(1.0_dp + dd(c))*(dd(a) - dd(b))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(4, a) = -(dd(a) - dd(b))*(dd(c) - dd(a))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        bb(a) = cc(4, a)*dd(a)
        ff = ff*(1.0_dp + dd(a))/(dd(a)*(dd(a) - dd(b)))**2
      end do
      bb(4) = -dd(1)*dd(2)*dd(3)*((dd(1) - dd(2))*(dd(2) - dd(3))*(dd(3) - dd(1)))**2
      ff = -ff/6.0_dp

      do i = 1, 4
        Ans = Ans + F(i)*(cc(i, 1)*ll(1) + cc(i, 2)*ll(2) + cc(i, 3)*ll(3) + bb(i))
      end do
      Ans = Ans*ff/(D(4) + hw)

      tetrahedron_integral = Ans*Det_t

    case (2)
      ! calculate integ d2k / |grad D| * F(k)

      ! obtaining |grad D|
      call utility_inv3(t, t_inverse, Det_t)
      t_inverse = t_inverse/Det_t

      GradD = 0.0_dp
      DO i = 1, 3
        DO j = 1, 3
          DO k = 1, 3
            GradD = GradD + t_inverse(i, k)*t_inverse(j, k)*(D(i + 1) - D(1))*(D(j + 1) - D(1))
          END DO
        END DO
      END DO
      GradD = SQRT(ABS(GradD))

      IF (hw < D(1)) THEN
        Ans = 0.0_dp
      ELSE IF (hw < D(2)) THEN
        ! parametrization
        x(1) = (hw - D(1))/(D(2) - D(1))
        x(2) = (hw - D(1))/(D(3) - D(1))
        x(3) = (hw - D(1))/(D(4) - D(1))
        ! Jacobian factor
        Jac = tetrahedron_jacobian(t, x, 1)
        ! integration formula
        F_uv(0) = F(1) + (F(2) - F(1))*x(1)
        F_uv(1) = (F(3) - F(1))*x(2) - (F(2) - F(1))*x(1)
        F_uv(2) = (F(4) - F(1))*x(3) - (F(2) - F(1))*x(1)
        Ans = Jac*(F_uv(0)/2.0_dp + (F_uv(1) + F_uv(2))/6.0_dp)/GradD
      ELSE IF (hw < D(3)) THEN
        ! parametrization
        x(1) = (hw - D(4))/(D(2) - D(4))
        x(2) = (hw - D(1))/(D(3) - D(1))
        x(3) = (hw - D(1))/(D(4) - D(1))

        !! triangle 1
        ! Jacobian factor
        Jac = tetrahedron_jacobian(t, x, 2)
        ! integration formula
        F_uv(0) = F(1) + (F(4) - F(1))*x(3)
        F_uv(1) = (F(2) - F(1))*x(1) + (F(4) - F(1))*(1.0_dp - x(1) - x(3))
        F_uv(2) = (F(3) - F(1))*x(2) - (F(4) - F(1))*x(3)
        Ans = Jac*(F_uv(0)/2.0_dp + (F_uv(1) + F_uv(2))/6.0_dp)

        !! triangle 2
        y = (hw - D(3))/(D(2) - D(3))
        ! Jacobian factor
        Jac = tetrahedron_jacobian(t, x, 3)
        ! integration formula
        F_uv(0) = F(1) + (F(2) - F(1))*y + (F(3) - F(1))*(1.0_dp - y)
        F_uv(1) = (F(2) - F(1))*(x(1) - y) + &
                  (F(3) - F(1))*(y - 1.0_dp) + (F(4) - F(1))*(1.0_dp - x(1))
        F_uv(2) = -(F(2) - F(1))*y + (F(3) - F(1))*(y - 1.0_dp + x(2))
        Ans = Ans + Jac*(F_uv(0)/2.0_dp + (F_uv(1) + F_uv(2))/6.0_dp)

        Ans = Ans/GradD
      ELSE IF (hw < D(4)) THEN
        ! parametrization
        x(1) = (hw - D(4))/(D(2) - D(4))
        x(2) = (hw - D(4))/(D(3) - D(4))
        x(3) = (hw - D(1))/(D(4) - D(1))
        ! Jacobian factor
        Jac = tetrahedron_jacobian(t, x, 4)
        ! integration formula
        F_uv(0) = F(1) + (F(4) - F(1))*x(3)
        F_uv(1) = (F(2) - F(1))*x(1) + (F(4) - F(1))*(1.0_dp - x(1) - x(3))
        F_uv(2) = (F(3) - F(1))*x(2) + (F(4) - F(1))*(1.0_dp - x(2) - x(3))
        Ans = Jac*(F_uv(0)/2.0_dp + (F_uv(1) + F_uv(2))/6.0_dp)/GradD
      ELSE
        Ans = 0.0_dp
      END IF
      tetrahedron_integral = Ans

    case (3)
      do i = 1, 3
        a = i
        b = mod(i, 3) + 1
        c = mod(i + 1, 3) + 1
        cc(a, a) = -(1.0_dp + dd(a))*(2.0_dp*dd(a)**3 + (3.0_dp - dd(b) - dd(c))*dd(a)**2 &
                                      - 2.0_dp*(dd(b) + dd(c))*dd(a) + dd(b)*dd(c))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(b, a) = -(1.0_dp + dd(a))*dd(a)*(1.0_dp + dd(b))*(dd(c) - dd(a))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(c, a) = (1.0_dp + dd(a))*dd(a)*(1.0_dp + dd(c))*(dd(a) - dd(b))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        cc(4, a) = -(1.0_dp + dd(a))*(dd(a) - dd(b))*(dd(c) - dd(a))*((dd(b) - dd(c))*dd(b)*dd(c))**2
        bb(a) = cc(4, a)*dd(a)
        ff = ff*(1.0_dp + dd(a))/(dd(a)*(dd(a) - dd(b)))**2
      end do
      bb(4) = -dd(1)*dd(2)*dd(3)*((dd(1) - dd(2))*(dd(2) - dd(3))*(dd(3) - dd(1)))**2
      ff = ff/2.0_dp
      do i = 1, 4
        Ans = Ans + F(i)*(cc(i, 1)*ll(1) + cc(i, 2)*ll(2) + cc(i, 3)*ll(3) + bb(i))
      end do
      Ans = Ans*ff/(D(4) + hw)**2

      tetrahedron_integral = Ans*Det_t
    case default
      tetrahedron_integral = 0.0_dp
    end select

    return
  end function tetrahedron_integral

  !=========================================================
  subroutine tetrahedron_sort(a, b1, b2, t)
    !===========================================!
    !A simple bubble sort subroutine for size 4 !
    !Assuming the size of a is four             !
    !===========================================!

    real(kind=dp), DIMENSION(4), INTENT(INOUT) :: a, b1, b2
    real(kind=dp), DIMENSION(3, 3), INTENT(INOUT) :: t
    real(kind=dp), DIMENSION(4) :: b1_temp, b2_temp
    real(kind=dp), DIMENSION(3, 4) :: t_temp
    INTEGER :: i, j
    INTEGER, DIMENSION(4) :: reference
    real(kind=dp) :: temp
    integer :: temp2

    DO i = 1, 4
      reference(i) = i
    END DO
    b1_temp = b1; b2_temp = b2
    DO j = 1, 3
      t_temp(j, 1) = 0
    END DO
    DO i = 2, 4
      DO j = 1, 3
        t_temp(j, i) = t(j, i - 1)
      END DO
    END DO
    DO i = 4, 1, -1
      DO j = 1, i - 1, +1
        IF (a(j) > a(j + 1)) THEN
          temp = a(j)
          a(j) = a(j + 1)
          a(j + 1) = temp
          temp2 = reference(j)
          reference(j) = reference(j + 1)
          reference(j + 1) = temp2
        END IF
      END DO
    END DO
    ! rearrange t(j,i)
    DO i = 2, 4
      DO j = 1, 3
        t(j, i - 1) = t_temp(j, reference(i)) - t_temp(j, reference(1))
      END DO
    END DO
    ! rearrange b(j,i)
    DO i = 1, 4
      b1(i) = b1_temp(reference(i))
      b2(i) = b2_temp(reference(i))
    END DO

  end subroutine tetrahedron_sort

!=========================================================
  function tetrahedron_jacobian(t, x, type)
    !=======================================!
    !                                       !
    ! Jacobian part of surface integrations !
    !                                       !
    !=======================================!
    use w90_constants, only: dp
    implicit none
    real(kind=dp) :: tetrahedron_jacobian
    real(kind=dp), DIMENSION(3, 3), INTENT(IN) :: t
    real(kind=dp), DIMENSION(3), INTENT(IN) :: x
    real(kind=dp), DIMENSION(3, 2) :: J
    real(kind=dp) :: y
    real(kind=dp) :: Ans
    INTEGER, INTENT(IN) :: type
    INTEGER :: j_, k, a, b, c, d

    IF (type == 1) THEN
      J(1, 1) = -x(1); J(1, 2) = -x(1)
      J(2, 1) = x(2); J(2, 2) = 0.0_dp
      J(3, 1) = 0.0_dp; J(3, 2) = x(3)
    ELSE IF (type == 2) THEN
      J(1, 1) = x(1); J(1, 2) = 0.0_dp
      J(2, 1) = 0.0_dp; J(2, 2) = x(2)
      J(3, 1) = 1.0_dp - x(1) - x(3); J(3, 2) = -x(3)
    ELSE IF (type == 3) THEN
      y = x(1)*(x(2) - 1.0_dp)*x(3)/(-x(2) + x(1)*x(2) + x(2)*x(3) - x(1)*x(3))
      J(1, 1) = x(1) - y; J(1, 2) = -y
      J(2, 1) = y - 1.0_dp; J(2, 2) = y - 1.0_dp + x(2)
      J(3, 1) = 1.0_dp - x(1); J(3, 2) = 0.0_dp
    ELSE
      J(1, 1) = x(1); J(1, 2) = 0.0_dp
      J(2, 1) = 0.0_dp; J(2, 2) = x(2)
      J(3, 1) = 1.0_dp - x(1) - x(3); J(3, 2) = 1.0_dp - x(2) - x(3)
    END IF
    Ans = 0.0_dp
    DO j_ = 1, 3
      DO k = 1, 3
        DO a = 1, 3
          DO b = 1, 3
            DO c = 1, 3
              DO d = 1, 3
                Ans = Ans + t(j_, a)*t(j_, b)*t(k, c)*t(k, d)*J(a, 1)*J(c, 2)*(J(b, 1)*J(d, 2) - J(b, 2)*J(d, 1))
              END DO
            END DO
          END DO
        END DO
      END DO
    END DO
    tetrahedron_jacobian = SQRT(ABS(Ans))

  end function tetrahedron_jacobian

  function tetrahedron_log1p(x)

    use w90_constants, only: dp

    implicit none

    real(kind=dp) :: tetrahedron_log1p
    real(kind=dp), intent(in) :: x
    real(kind=dp) :: y, z

    if (ABS(x) > 0.5_dp) then
      tetrahedron_log1p = LOG(ABS(1.0_dp + x))
    else
      y = 1.0_dp + x
      z = y - 1.0_dp
      if (z == 0) then
        tetrahedron_log1p = x
      else
        tetrahedron_log1p = x*LOG(y)/z
      end if
    end if

  end function tetrahedron_log1p

end module w90_tetrahedron