subroutine frantic_get_se(zf)
  
  !  get the electron source to the plasma due to ionization of neutrals
  !  #/m**3/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,SORE(1:nzonec),zf,0)

  return
end subroutine frantic_get_se

subroutine frantic_get_seb(zf)
  
  !  get the electron source to the fast ion population (leading to a
  !  fast neutral source) ... #/m**3/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TSTOR1(1:nzonec,1),zf,0)

  return
end subroutine frantic_get_seb

subroutine frantic_get_scx(zf)
  
  !  get the charge exchange reaction rate  #/m**3/sec 

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,SCX(1:nzonec),zf,0)

  return
end subroutine frantic_get_scx

subroutine frantic_get_pcx(zf)
  
  !  get the charge exchange power  W/m**3  lost to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PCX(1:nzonec),zf,0)

  return
end subroutine frantic_get_pcx

subroutine frantic_get_pii(zf)
  
  !  get the ionization source power  W/m**3  to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PII(1:nzonec),zf,0)

  return
end subroutine frantic_get_pii

subroutine frantic_get_tqcx(zf)
  
  !  get the charge exchange torque density  Nt-m/m**3  lost to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TQCX(1:nzonec),zf,0)

  return
end subroutine frantic_get_tqcx

subroutine frantic_get_tqii(zf)
  
  !  get the ionization source torque density  Nt-m/m**3  to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TQII(1:nzonec),zf,0)

  return
end subroutine frantic_get_tqii

subroutine frantic_get_pcxsf(zf)
  
  !  get the charge exchange source friction  W/m**3 to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PCXSF(1:nzonec),zf,0)

  return
end subroutine frantic_get_pcxsf

subroutine frantic_get_piisf(zf)
  
  !  get the ionization source friction  W/m**3 to ions

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PIISF(1:nzonec),zf,0)

  return
end subroutine frantic_get_piisf


subroutine frantic_get_n0(ik,zf)
  
  !  for neutral species 'ik'
  !  get the neutral density #/cm**3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  integer, intent(in) :: ik               ! neutral specie index
  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  if(ik.eq.0) then
    zf=0
  else
    call frantic_intrp_out(zconv,DNEUT(1:nzonec,ik)+DCOLD(1:nzonec,ik),zf,1)
  end if

  return
end subroutine frantic_get_n0

subroutine frantic_get_t0(ik,zf)
  
  !  for neutral species 'ik'
  !  get the neutral "temperature", KeV

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  integer, intent(in) :: ik             ! neutral specie index
  real(fp), intent(out) :: zf(nx_user)  ! the output profile.
  real(fp), parameter :: zconv = 1.0_fp ! leave as KeV

  if(ik.eq.0) then
    zf=0
  else
    call frantic_intrp_out(zconv,TNEUT(1:nzonec,ik),zf,1)
  end if

  return
end subroutine frantic_get_t0

subroutine frantic_get_Si(ik,zf)
  
  !  for neutral species 'ik'
  !  get the ionization ion source, #/m**3/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  integer, intent(in) :: ik               ! neutral specie index
  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  if(ik.eq.0) then
    zf=0
  else
    call frantic_intrp_out(zconv,SORI(1:nzonec,ik),zf,0)
  end if

  return
end subroutine frantic_get_Si

subroutine frantic_get_totalSce(ik,zsce)

  !  for neutral species 'ik'
  !  get the total ionization ion source, equiv. flux #/m**2/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  integer, intent(in) :: ik      ! neutral specie index
  real(fp), intent(out) :: zsce

  integer i

  zsce=0
  if(ik.gt.0) then
    do i=1,nzonec
      zsce=zsce+SORI(i,ik)*vol(i)
    end do
    zsce=1.0e4_fp*zsce/(aminor*6.2831853071795862_fp)
  end if

  return
end subroutine frantic_get_totalSce

subroutine frantic_get_Vphi0(ik,zf)
  
  !  for neutral species 'ik'
  !  get the average neutral toroidal velocity, m/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  integer, intent(in) :: ik                ! neutral specie index
  real(fp), intent(out) :: zf(nx_user)     ! the output profile.
  real(fp), parameter :: zconv = 1.0e-2_fp ! MKS conversion

  if(ik.eq.0) then
    zf=0
  else
    call frantic_intrp_out(zconv,VPHI0F(1:nzonec,ik),zf,1)
  end if

  return
end subroutine frantic_get_Vphi0

subroutine frantic_get_sflx01(zf)
  
  !  get the total div(influx) of (electrons carried by) neutral atoms
  !  #/m**3/sec 

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,SFLX0M(1,1:nzonec),zf,0)

  return
end subroutine frantic_get_sflx01

subroutine frantic_get_sflx02(zf)
  
  !  get the total div(outflux) of (electrons carried by) neutral atoms
  !  #/m**3/sec 

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,SFLX0M(2,1:nzonec),zf,0)

  return
end subroutine frantic_get_sflx02

subroutine frantic_get_pflx01(zf)
  
  !  get the total div(influx) of (power carried by) neutral atoms
  !  W/m**3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PFLX0M(1,1:nzonec),zf,0)

  return
end subroutine frantic_get_pflx01

subroutine frantic_get_pflx02(zf)
  
  !  get the total div(outflux) of (power carried by) neutral atoms
  !  W/m**3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,PFLX0M(2,1:nzonec),zf,0)

  return
end subroutine frantic_get_pflx02

subroutine frantic_get_tqflx01(zf)
  
  !  get the total div(influx) of (ang. momentum carried by) neutral atoms
  !  Nt-m/m**3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TQFLX0M(1,1:nzonec),zf,0)

  return
end subroutine frantic_get_tqflx01

subroutine frantic_get_tqflx02(zf)
  
  !  get the total div(outflux) of (ang. momentum carried by) neutral atoms
  !  Nt-m/m**3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TQFLX0M(2,1:nzonec),zf,0)

  return
end subroutine frantic_get_tqflx02

subroutine frantic_get_tqflx0(zf)
  
  !  get the total div(flux) of momentum of neutral atoms
  !  Nt-m/m**3

  !  for legacy reasons, return of the combined flux is offered for momentum
  !  only...

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,TQFLX0(1:nzonec),zf,0)

  return
end subroutine frantic_get_tqflx0

subroutine frantic_get_vsor_Z(zf)

  !  get the total volume neutral source * Z  #/m^3/sec

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,vsor_zw(1:nzonec),zf,0)

  return
end subroutine frantic_get_vsor_Z

subroutine frantic_get_vsor_en(zf)

  !  get the total volume neutral energy source  W/m^3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,vsor_en(1:nzonec),zf,0)

  return
end subroutine frantic_get_vsor_en

subroutine frantic_get_vsor_mo(zf)

  !  get the total volume neutral ang. momentum source   Nt-m/m^3

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: zf(nx_user)    ! the output profile.
  real(fp), parameter :: zconv = 1.0e6_fp ! MKS conversion

  call frantic_intrp_out(zconv,vsor_mo(1:nzonec),zf,0)

  return
end subroutine frantic_get_vsor_mo

subroutine frantic_get_dvol(dvols)

  !  return the volume elements on the user grid

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  real(fp), intent(out) :: dvols(nx_user)  ! returned in m^3
  real(fp), parameter :: zconv = 1.0e-6_fp ! MKS conversion

  integer :: ix

  do ix=1,nx_user
    dvols(ix) = (volxb_user(ix+1)-volxb_user(ix))*zconv
  end do

  return
end subroutine frantic_get_dvol

!----------------------------------------------------------------
!  interpolation routine
!

subroutine frantic_intrp_out(zconv,fdata,zf,imethod)

  use iso_c_binding, only: fp => c_double
  use physconst_mod, only: zero
  use ezspline_type, only: ezspline1
  use ezspline_obj, only: ezspline_preinit
  use ezspline, only: ezspline_init, ezspline_free, ezspline_setup, ezspline_interp
  use frantic_module
  implicit none

  !  use Hermite interpolation to map data to the user specified grid

  real(fp), intent(in) :: zconv          ! MKS conversion factor
  real(fp), intent(in) :: fdata(nzonec)  ! data on FRANTIC grid, to interpolate
  real(fp), intent(out) :: zf(nx_user)   ! interpolation results
  integer, intent(in) :: imethod       ! method flag

  !  imethod=0: Spline interpolate integral of profile; take derivative.
  !     (this method guarantees preservation of ptcl/momentum/energy balance).
  ! 
  !  imethod=1: take log of profile, Hermite interpolate, exponentiate result.
  !  imethod=2: direct Hermite interpolation.

  !--------------------

  type(ezspline1) :: zspline

  real(fp) :: zfbuf(nzonec+2),zfbufi(nzonec+1),ztest,zfloor,zlim1,zlim2
  real(fp) :: zfi(nxb_user)

  integer :: i,iok

  !--------------------

  if(imethod.eq.0) then

    zfbufi(1)=0
    do i=1,nzonec
      zfbufi(i+1)=zfbufi(i)+(tvol(i+1)-tvol(i))*fdata(i)
    end do

  else if(imethod.eq.1) then

    ! sanity check, if using log/exp method

    ztest=maxval(fdata)
    if(ztest.le.ZERO) then
      zf=ZERO
      return
    end if

    zfloor=1.0e-30_fp*ztest

    zfbuf(2:nzonec+1)=log(max(zfloor,fdata))

  else if(imethod.eq.2) then

    zfbuf(2:nzonec+1)=fdata

  end if

  call ezspline_preinit(zspline)  ! made a difference to the pathscale compiler
  if(imethod.eq.0) then

    ! form cubic spline of integral

    call ezspline_init(zspline,nzonec+1,(/1, 0/),iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_init error.')
    zspline%bcval1min = 0  ! df/dx -> 0 on axis
    zspline%x1 = xb(1:nzonec+1)

    call ezspline_setup(zspline,zfbufi,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_setup error.')

    ! do the interpolation of the integral function

    call ezspline_interp(zspline,nxb_user,xb_user,zfi,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_interp error.')

    ! release spline memory

    call ezspline_free(zspline,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_free error.')

    ! compute user results

    do i=1,nx_user
      zf(i)=(zfi(i+1)-zfi(i))/(volxb_user(i+1)-volxb_user(i))
    end do

  else if(imethod.gt.0) then

    ! axial extrapolation

    if(imethod.eq.1) then
      zlim1=zfbuf(2)-0.2_fp
      zlim2=zfbuf(2)+0.2_fp
    else
      zlim1=min(1.1_fp*zfbuf(2),0.9_fp*zfbuf(2))
      zlim2=max(1.1_fp*zfbuf(2),0.9_fp*zfbuf(2))
    end if

    ztest=1.125_fp*zfbuf(2)-0.125_fp*zfbuf(3)
    zfbuf(1)=max(zlim1,min(zlim2,ztest))

    ! edge extrapolation

    if(imethod.eq.1) then
      zlim1=zfbuf(nzonec+1)-1.0_fp
      zlim2=zfbuf(nzonec+1)+1.0_fp
    else
      zlim1=min(2.0_fp*zfbuf(nzonec+1),0.5_fp*zfbuf(nzonec+1))
      zlim2=max(2.0_fp*zfbuf(nzonec+1),0.5_fp*zfbuf(nzonec+1))
    end if

    ztest=1.5_fp*zfbuf(nzonec+1)-0.5_fp*zfbuf(nzonec)
    zfbuf(nzonec+2)=max(zlim1,min(zlim2,ztest))

    ! form Hermite Spline

    call ezspline_init(zspline,nzonec+2,(/1, 0/),iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_init failure.')
    zspline%bcval1min = 0  ! df/dx -> 0 on axis
    zspline%x1(2:nzonec+1) = x
    zspline%x1(1)=xb(1)
    zspline%x1(nzonec+2)=xb(nzonec+1)
    zspline%isHermite = 1

    call ezspline_setup(zspline,zfbuf,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_setup failure.')

    ! do the interpolation

    call ezspline_interp(zspline,nx_user,x_user,zf,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_interp failure.')

    ! release spline memory

    call ezspline_free(zspline,iok)
    if(iok.ne.0) call errmsg_exit(' ?frantic_output: ezspline_free failure.')

    ! re-exponentiate data if necessary

    if(imethod.eq.1) zf=exp(zf)

  end if

  ! units conversion

  zf=zf*zconv

  return
end subroutine frantic_intrp_out

subroutine frantic_get_outflux(ik, zflux, zengy)

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  ! get outflux rate and average energy for species 'ik'

  integer, intent(in) :: ik       ! neutral specie index
  real(fp), intent(out) :: zflux    ! outflux rate (#/m**2/sec)
  real(fp), intent(out) :: zengy    ! average energy (KeV/ptcl)

  if(ik.eq.0) then
    zflux=0
    zengy=0
  else
    zflux=outflx(ik)*1.0e4_fp
    zengy=0.001_fp*eescav(ik)/(1.602e-19_fp)
  end if

  return
end subroutine frantic_get_outflux

subroutine frantic_get_inps(zfluxi)

  use iso_c_binding, only: fp => c_double
  use frantic_module
  implicit none

  ! edge source: return the influx across the boundary, in #atoms/sec
  ! return ZERO for volume source

  real(fp), intent(out) :: zfluxi

  !--------------------
  integer :: ik,ink,iz,ix,inx
  real(fp), dimension(:), allocatable :: dvols,sflx1
  !--------------------

  if(vsflag) then
    zfluxi=0.0_fp
    return
  end if

  ik=nneut_s0
  if(ik.eq.0) then
    zfluxi=0.0_fp
    return
  end if

  ink=nspec(ik)
  iz=xzplas(ink)+0.1_fp

  call frantic_get_nx_user(inx)
  allocate(dvols(inx),sflx1(inx))

  call frantic_get_dvol(dvols)

  call frantic_get_sflx01(sflx1)

  zfluxi=0.0_fp

  do ix=1,inx
    zfluxi = zfluxi + dvols(ix)*sflx1(ix)
  end do

  zfluxi=zfluxi/iz

  deallocate(dvols,sflx1)

  return
end subroutine frantic_get_inps
