splint.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------!
! Copyright (c) 2018 Peter Grünberg Institut, Forschungszentrum Jülich, Germany           !
! This file is part of Jülich KKR code and available as free software under the conditions!
! of the MIT license as expressed in the LICENSE.md file in more detail.                  !
!-----------------------------------------------------------------------------------------!

!------------------------------------------------------------------------------------
!> Summary: This routine returns a cubic-spline interpolated value `y` and the derivative `yderiv`.
!> Author: 
!> Given the arrays `xa(1:n)` and `ya(1:n)` of length `n`, which tabulate a
!> function (with the xai's in order), and given the array `y2a(1:n)`, which
!> is the output from spline above, and given a value of `x`, this routine
!> returns a cubic-spline interpolated value `y` and the derivative `yderiv`.
!> We will nd the right place in the table by means of bisection.
!> This is optimal if sequential calls to this routine are at random
!> values of `x`. If sequential calls are in order, and closely
!> spaced, one would do better to store previous values of
!> `klo` and `khi` and test if they remain appropriate on the next call.
!------------------------------------------------------------------------------------
!> @note Taken from "Numerical Recipes in Fortran 77", W.H.Press et al.
!> @endnote
!------------------------------------------------------------------------------------
module mod_splint

  use :: mod_datatypes, only: dp
  private :: dp

  public :: splint_real

contains

  !-------------------------------------------------------------------------------
  !> Summary: This routine returns a cubic-spline interpolated value `y` and the derivative `yderiv`.
  !> Author: 
  !> Category: numerical-tools, KKRhost, voronoi, kkrimp, kkrscatter
  !> Deprecated: False 
  !> Given the arrays `xa(1:n)` and `ya(1:n)` of length `n`, which tabulate a
  !> function (with the xai's in order), and given the array `y2a(1:n)`, which
  !> is the output from spline above, and given a value of `x`, this routine
  !> returns a cubic-spline interpolated value `y` and the derivative `yderiv`.
  !> We will nd the right place in the table by means of bisection.
  !> This is optimal if sequential calls to this routine are at random
  !> values of `x`. If sequential calls are in order, and closely
  !> spaced, one would do better to store previous values of
  !> `klo` and `khi` and test if they remain appropriate on the next call.
  !-------------------------------------------------------------------------------
  !> @note Taken from "Numerical Recipes in Fortran 77", W.H.Press et al.
  !> @endnote
  !-------------------------------------------------------------------------------
  subroutine splint_real(xa, ya, y2a, n, x, y, yderiv)
    implicit none
    real (kind=dp), parameter :: eps = 1e-14_dp
    integer :: n
    real (kind=dp) :: x, y, yderiv
    real (kind=dp), dimension(*) :: xa, ya, y2a
    integer :: k, khi, klo
    real (kind=dp) :: a, b, h

    klo = 1
    khi = n
100 if (khi-klo>1) then
      k = (khi+klo)/2
      if (xa(k)>x) then
        khi = k
      else
        klo = k
      end if
      go to 100
    end if
    ! klo and khi now bracket the input value of x.
    h = xa(khi) - xa(klo)
    ! The xa's must be distinct.
    if (abs(h)<eps) stop 'bad xa input in splint'
    ! Cubic spline polynomial is now evaluated.
    a = (xa(khi)-x)/h
    b = (x-xa(klo))/h
    y = a*ya(klo) + b*ya(khi) + ((a**3-a)*y2a(klo)+(b**3-b)*y2a(khi))*(h**2)/6.e0_dp
    yderiv = (ya(khi)-ya(klo))/h - ((3.e0_dp*a*a-1.e0_dp)*y2a(klo)-(3.e0_dp*b*b-1.e0_dp)*y2a(khi))*h/6.e0_dp

    return
  end subroutine splint_real


  !-------------------------------------------------------------------------------
  !> Summary: This routine returns a cubic-spline interpolated value `y` and the derivative `yderiv`.
  !> Author: 
  !> Category: numerical-tools, KKRhost
  !> Deprecated: False 
  !> Complex version of `splint_real`.
  !-------------------------------------------------------------------------------
  subroutine splint_complex(xa, ya, y2a, n, x, y, yderiv)
    implicit none
    real (kind=dp), parameter :: eps = 1e-14_dp
    integer :: n
    real (kind=dp) :: x
    complex (kind=dp) :: y, yderiv
    real (kind=dp), dimension(*) :: xa
    complex (kind=dp), dimension(*) :: ya, y2a
    integer :: k, khi, klo
    real (kind=dp) :: a, b, h

    klo = 1
    khi = n
100 if (khi-klo>1) then
      k = (khi+klo)/2
      if (xa(k)>x) then
        khi = k
      else
        klo = k
      end if
      go to 100
    end if
    ! klo and khi now bracket the input value of x.
    h = xa(khi) - xa(klo)
    ! The xa's must be distinct.
    if (abs(h)<eps) stop 'bad xa input in splint'
    ! Cubic spline polynomial is now evaluated.
    a = (xa(khi)-x)/h
    b = (x-xa(klo))/h
    y = a*ya(klo) + b*ya(khi) + ((a**3-a)*y2a(klo)+(b**3-b)*y2a(khi))*(h**2)/6.e0_dp
    yderiv = (ya(khi)-ya(klo))/h - ((3.e0_dp*a*a-1.e0_dp)*y2a(klo)-(3.e0_dp*b*b-1.e0_dp)*y2a(khi))*h/6.e0_dp

    return
  end subroutine splint_complex

end module mod_splint