#if defined HAVE_CONFIG_H
#include "config.h"
#endif

module ldaxc_basket

  use gridxc_precision, only: dp

  use fruit
  use gridxc_ldaxc

  implicit none

  ! Number of grid points
  integer, parameter, private :: npts = 45

  ! Grid extension: from -grid_max to grid_max
  real(dp), parameter, private :: grid_max = 6.0_dp

  ! Normal distribution width for spin up and down (must be < grid_max / 6)
  real(dp), parameter, private :: sigma(2) = (0.6_dp, 0.5_dp)

  ! Tolerance (square root of machine precision should be fine)
  real(dp), parameter, private :: ldaxc_tol = sqrt(epsilon(1.0_dp))

  ! Arrays to store the density values (rhov) and gradients (rhog)
  real(dp), allocatable, private :: rhog(:,:,:), rhov(:,:,:)

  ! Internal functions and subroutines
  private :: idx_to_pos

contains

  ! Translate array indices to coordinates between -grid_max and +grid_max
  function idx_to_pos(index, offset) result(pos)

    implicit none

    integer, intent(in) :: index
    real(dp),intent(in), optional :: offset
    real(dp) :: pos

    pos = ((2.0_dp * real(index, dp) - real(npts, dp) - 1.0_dp) * grid_max) / &
&         (real(npts, dp) - 1.0_dp)
    if ( present(offset) ) then
      pos = pos - offset
    end if

  end function idx_to_pos

  ! Initialize rhov as a pair of normal probability density functions
  ! for spin up and spin down and calculate its gradient rhog
  subroutine setup_ldaxc

    implicit none

    integer :: is, ix, iy, iz
    real(dp) :: a, b(2), r2

    allocate(rhog(npts, npts, npts, 2))
    allocate(rhov(npts, npts, npts, 2))

    ! Spin-polarized density (1=up, 2=down)
    do is=1,2

      ! Normal distribution prefactor: (sigma*sqrt(2*pi))^-1
      a = 1.0_dp / (sigma(is) * sqrt(8.0_dp * atan(1.0_dp))

      ! Distribution centers:
      !   - positive third of x grid for spin up (+2*grid_max/3)
      !   - negative third of x grid for spin down (-2*grid_max/3)
      b =  real(3 - 2*is, dp) * 2.0_dp * grid_max / 3.0_dp

      do iz=1,npts
        do iy=1,npts
          do ix=1,npts
            r2 = idx_to_pos(ix, b)**2 + &
&                idx_to_pos(iy)**2 + &
&                idx_to_pos(iz)**2
            rhov(ix,iy,iz,is) = a * exp(-0.5_dp * r2 / sigma(is)**2)
            rhog(ix,iy,iz,is) = -sqrt(r2) * rhov(ix,iy,iz) / sigma(is)
          end do
        end do
      end do

    end do

  end subroutine setup_ldaxc

  ! Free memory
  subroutine teardown_ldaxc

    deallocate(rhog)
    deallocate(rhov)

  end subroutine teardown_ldaxc

  subroutine test_ldaxc_exchng_irel0

    implicit none

  end subroutine test_ldaxc_exchng_irel0

  subroutine test_ldaxc_exchng_irel1

    implicit none

  end subroutine test_ldaxc_exchng_irel1

  subroutine test_ldaxc_exchng_nspin1

    implicit none

  end subroutine test_ldaxc_exchng_nspin1

  subroutine test_ldaxc_exchng_nspin2

    implicit none

  end subroutine test_ldaxc_exchng_nspin2

  subroutine test_ldaxc_pw92c_nspin1

    implicit none

  end subroutine test_ldaxc_pw92c_nspin1

  subroutine test_ldaxc_pw92c_nspin2

    implicit none

  end subroutine test_ldaxc_pw92c_nspin2

  subroutine test_ldaxc_pw92xc_irel0

    implicit none

  end subroutine test_ldaxc_pw92xc_irel0

  subroutine test_ldaxc_pw92xc_irel1

    implicit none

  end subroutine test_ldaxc_pw92xc_irel1

  subroutine test_ldaxc_pw92xc_nspin1

    implicit none

  end subroutine test_ldaxc_pw92xc_nspin1

  subroutine test_ldaxc_pw92xc_nspin2

    implicit none

  end subroutine test_ldaxc_pw92xc_nspin2

  subroutine test_ldaxc_pzxc_irel0

    implicit none

  end subroutine test_ldaxc_pzxc_irel0

  subroutine test_ldaxc_pzxc_irel1

    implicit none

  end subroutine test_ldaxc_pzxc_irel1

  subroutine test_ldaxc_pzxc_nspin1

    implicit none

  end subroutine test_ldaxc_pzxc_nspin1

  subroutine test_ldaxc_pzxc_nspin2

    implicit none

  end subroutine test_ldaxc_pzxc_nspin2

  subroutine test_ldaxc_main_nolibxc

    implicit none

  end subroutine test_ldaxc_main_nolibxc

#ifdef HAVE_LIBXC
  subroutine test_ldaxc_main_libxc

    implicit none

  end subroutine test_ldaxc_main_libxc
#endif

  subroutine fruit_basket

    implicit none

    call setup_ldaxc

    call test_ldaxc_exchng_irel0
    call test_ldaxc_exchng_irel1
    call test_ldaxc_exchng_nspin1
    call test_ldaxc_exchng_nspin2
    call test_ldaxc_pw92c_nspin1
    call test_ldaxc_pw92c_nspin2
    call test_ldaxc_pw92xc_irel0
    call test_ldaxc_pw92xc_irel1
    call test_ldaxc_pw92xc_nspin1
    call test_ldaxc_pw92xc_nspin2
    call test_ldaxc_pzxc_irel0
    call test_ldaxc_pzxc_irel1
    call test_ldaxc_pzxc_nspin1
    call test_ldaxc_pzxc_nspin2

    call test_ldaxc_main_nolibxc
#ifdef HAVE_LIBXC
    call test_ldaxc_main_libxc
#endif

    call teardown_ldaxc

  end subroutine fruit_basket

end module ldaxc_basket
