! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !
! @@                                                                @@ !
! @@       PROGRAM  ASCOT 2014.440 (ver.4.40)                       @@ !
! @@     "Abinitio Simulation Code for Quantum Transport"           @@ !
! @@                                                                @@ !
! @@                                                                @@ !
! @@  AUTHOR(S): Naoki WATANABE, Nobutaka NISHIKAWA (Mizuho I.R.)   @@ !
! @@             Hisashi KONDO (Univ. Tokyo)                        @@ !
! @@                                                09/May/2014     @@ !
! @@                                                                @@ !
! @@  Contact address: Phase System Consortium                      @@ !
! @@                                                                @@ !
! @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ !

subroutine Spline__set( spline, vf, vx_out, N )
  use ac_misc_module

  implicit none
  type(Spline_type), intent(out) :: spline
  integer, intent(in)       :: N
  real(8), intent(in)       :: vf(N)
  real(8), intent(in)       :: vx_out(N)

  real(8), allocatable :: vdx(:)
  real(8), allocatable :: vdf(:)
  real(8), allocatable ::  vu(:)
  integer       :: i

  spline%N = N 

  allocate( vdx(spline%N) )
  allocate( vdf(spline%N) )
  allocate(  vu(spline%N) )

  allocate( spline%vf(spline%N) )
  allocate( spline%vx(spline%N) )

  do i=1, spline%N
     spline%vf(i) = vf(i)
     spline%vx(i) = vx_out(i)
  end do

  allocate( spline%vb(spline%N) )
  allocate( spline%vc(spline%N) )
  allocate( spline%vd(spline%N) )

  do i=1, spline%N-1
     vdx(i) = vx_out(i+1) - vx_out(i+0)
  end do
  vdx(spline%N)=0.d0

  do i=1, spline%N-1
     vdf(i) = (vf(i+1)-vf(i))*(1.0/vdx(i))
  end do
  vdf(spline%N) = 0.d0

  spline%vc(1) = 0.d0
  do i=2, spline%N-1
     spline%vc(i) = (vdf(i+0)-vdf(i-1))*3.0
  end do
  spline%vc(spline%N) = 0.d0

  vu(1) = 0.d0
  do i=2, spline%N-1
     vu(i) = 1.0/( 2*(vdx(i+1)+vdx(i)) - vdx(i)*vdx(i)*vu(i-1) )
  end do
  vu(spline%N) = 0.d0

  do i=2, spline%N-1
     spline%vc(i) = spline%vc(i) - spline%vc(i-1)*(vdx(i-1)*vu(i-1))
  end do
  do i=spline%N-1, 2, -1
     spline%vc(i) = (spline%vc(i) - spline%vc(i+1)*vdx(i))*vu(i)
  end do

  do i=1, spline%N-1
     spline%vd(i) = (spline%vc(i+1)-spline%vc(i))*(1.0/(3.0*vdx(i)))
     spline%vb(i) = vdf(i) - spline%vc(i)*vdx(i) - spline%vd(i)*(vdx(i)*vdx(i))
  end do
  spline%vb(spline%N) = 0.d0
  spline%vd(spline%N) = 0.d0

  deallocate( vdx, vdf, vu )

  return
end subroutine Spline__set

subroutine Spline__reset( spline, vf )
  use ac_misc_module

  implicit none
  type(Spline_type), intent(inout) :: spline
  real(8), intent(in)       :: vf(spline%N)


  real(8), allocatable :: vdx(:)
  real(8), allocatable :: vdf(:)
  real(8), allocatable ::  vu(:)
  integer       :: i

  allocate( vdx(spline%N) )
  allocate( vdf(spline%N) )
  allocate(  vu(spline%N) )

  do i=1, spline%N
     spline%vf(i) = vf(i)
  end do

  do i=1, spline%N-1
     vdx(i) = spline%vx(i+1) - spline%vx(i+0)
  end do
  vdx(spline%N)=0.d0

  do i=1, spline%N-1
     vdf(i) = (vf(i+1)-vf(i))*(1.0/vdx(i))
  end do
  vdf(spline%N) = 0.d0

  spline%vc(1) = 0.d0
  do i=2, spline%N-1
     spline%vc(i) = (vdf(i+0)-vdf(i-1))*3.0
  end do
  spline%vc(spline%N) = 0.d0

  vu(1) = 0.d0
  do i=2, spline%N-1
     vu(i) = 1.0/( 2*(vdx(i+1)+vdx(i)) - vdx(i)*vdx(i)*vu(i-1) )
  end do
  vu(spline%N) = 0.d0

  do i=2, spline%N-1
     spline%vc(i) = spline%vc(i) - spline%vc(i-1)*(vdx(i-1)*vu(i-1))
  end do
  do i=spline%N-1, 2, -1
     spline%vc(i) = (spline%vc(i) - spline%vc(i+1)*vdx(i))*vu(i)
  end do

  do i=1, spline%N-1
     spline%vd(i) = (spline%vc(i+1)-spline%vc(i))*(1.0/(3.0*vdx(i)))
     spline%vb(i) = vdf(i) - spline%vc(i)*vdx(i) - spline%vd(i)*(vdx(i)*vdx(i))
  end do
  spline%vb(spline%N) = 0.d0
  spline%vd(spline%N) = 0.d0

  deallocate( vdx, vdf, vu )

  return
end subroutine Spline__reset

subroutine Spline_deallocate(spline)
  use ac_misc_module

  implicit none
  type(Spline_type) :: spline

  if( associated(spline%vx) ) deallocate(spline%vx)
  if( associated(spline%vf) ) deallocate(spline%vf)
  if( associated(spline%vb) ) deallocate(spline%vb)
  if( associated(spline%vc) ) deallocate(spline%vc)
  if( associated(spline%vd) ) deallocate(spline%vd)

  return
end subroutine Spline_deallocate
