subroutine psichi2uvt_reg( u, v,  psi, chi)
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    psichi2uvt_reg
!     prgmmr:    barker, d   org:  np22              date:  2000-02-03
!
! abstract:  Calculate adjoint of psi and chi from adjoint of
!            wind components u and v.
!
! program history log:
!   2000/02/03   barker, dale - creation of F90 version
!   2001/10/30   barker       - parallel version
!   2003/09/05   parrish      - adapted to unified NCEP 3dvar
!   2003/10/17   wu, wanshu   - first index Y second X
!   2004-06-22   treadon      - update documentation
!   2008-04-23   safford      - rm unused vars
!   2009-04-19   derber       - modify to fit gsi
!
!   input argument list:
!     u - adjoint of zonal wind component
!     v - adjoint of meridional wind component
!
!   output argument list:
!     psi - adjoint of streamfunction
!     chi - adjoint of velocity potential
!
! remarks:
!    The method used is
!       u = ( -dpsi/dy + dchi/dx )
!       v = (  dpsi/dx + dchi/dy )
!
!    The assumptions made in this routine are:
!       - unstaggered grid,
!       - lateral boundary conditions - dpsi/dn, dchi/dn = 0 (FCT)
!       - dy=rearth*dph , dx=cos(ph)*rearth*dlm (dx,dy is rotated grid)
!
! attributes:
!   language: f90
!   machine:  ibm rs/6000 sp
!
!$$$
  use kinds, only: r_kind,i_kind
  use constants, only: zero,half
  use gridmod, only:  coeffx,coeffy,nlat,nlon
  implicit none

  real(r_kind),intent(inout) :: u(nlat,nlon)   ! u wind comp (m/s)
  real(r_kind),intent(inout) :: v(nlat,nlon)   ! v wind comp (m/s)
  real(r_kind),intent(inout) :: psi(nlat,nlon) ! Stream function
  real(r_kind),intent(inout) :: chi(nlat,nlon) ! Velocity potential

  integer(i_kind)           :: i, j           ! Loop counters.
  real(r_kind)              :: coeffx_u       ! Multiplicative coefficient.
  real(r_kind)              :: coeffy_u       ! Multiplicative coefficient.
  real(r_kind)              :: coeffx_v       ! Multiplicative coefficient.
  real(r_kind)              :: coeffy_v       ! Multiplicative coefficient.

!------------------------------------------------------------------------------
!  [1.0] Initialise:
!------------------------------------------------------------------------------

  psi=zero
  chi=zero

!------------------------------------------------------------------------------
!     [4.0] Corner points (assume average of surrounding points - poor?):
!------------------------------------------------------------------------------

!    [4.1] Bottom-left point:

  u(2,1) = u(2,1) + half * u(1,1)
  u(1,2) = u(1,2) + half * u(1,1)
  v(2,1) = v(2,1) + half * v(1,1)
  v(1,2) = v(1,2) + half * v(1,1)

!    [4.2] Top-left point:

  u(nlat-1,1) = u(nlat-1,1) + half * u(nlat,1)
  u(nlat  ,2) = u(nlat  ,2) + half * u(nlat,1)
  v(nlat-1,1) = v(nlat-1,1) + half * v(nlat,1)
  v(nlat  ,2) = v(nlat  ,2) + half * v(nlat,1)

!    [4.3] Bottom-right point:

  u(2,nlon  ) = u(2,nlon  ) + half * u(1,nlon)
  u(1,nlon-1) = u(1,nlon-1) + half * u(1,nlon)
  v(2,nlon  ) = v(2,nlon  ) + half * v(1,nlon)
  v(1,nlon-1) = v(1,nlon-1) + half * v(1,nlon)

!    [4.4] Top-right point:

  u(nlat-1,nlon  ) = u(nlat-1,nlon  ) + half * u(nlat,nlon)
  u(nlat  ,nlon-1) = u(nlat  ,nlon-1) + half * u(nlat,nlon)
  v(nlat-1,nlon  ) = v(nlat-1,nlon  ) + half * v(nlat,nlon)
  v(nlat  ,nlon-1) = v(nlat  ,nlon-1) + half * v(nlat,nlon)

!------------------------------------------------------------------------------
! [3.0] Compute u, v at domain boundaries:
!------------------------------------------------------------------------------

!    [3.4] Northern boundaries:

  do j = 2,nlon-1
     coeffy_u = coeffy(nlat,j) * u(nlat,j)
     coeffx_u = coeffx(nlat,j) * u(nlat,j)
     coeffy_v = coeffy(nlat,j) * v(nlat,j)
     coeffx_v = coeffx(nlat,j) * v(nlat,j)

     psi(nlat  ,j+1) = psi(nlat  ,j+1) + coeffx_v
     psi(nlat  ,j-1) = psi(nlat  ,j-1) - coeffx_v
     chi(nlat  ,j  ) = chi(nlat  ,j  ) + coeffy_v
     chi(nlat-2,j  ) = chi(nlat-2,j  ) - coeffy_v

     psi(nlat  ,j  ) = psi(nlat  ,j  ) - coeffy_u
     psi(nlat-2,j  ) = psi(nlat-2,j  ) + coeffy_u
     chi(nlat  ,j+1) = chi(nlat  ,j+1) + coeffx_u
     chi(nlat  ,j-1) = chi(nlat  ,j-1) - coeffx_u
  end do

!    [3.3] Southern boundaries:

  do j = 2,nlon-1
     coeffy_u = coeffy(1,j) * u(1,j)
     coeffx_u = coeffx(1,j) * u(1,j)
     coeffy_v = coeffy(1,j) * v(1,j)
     coeffx_v = coeffx(1,j) * v(1,j)

     psi(1,j+1) = psi(1,j+1) + coeffx_v
     psi(1,j-1) = psi(1,j-1) - coeffx_v
     chi(3,j  ) = chi(3,j  ) + coeffy_v
     chi(1,j  ) = chi(1,j  ) - coeffy_v

     psi(3,j  ) = psi(3,j  ) - coeffy_u
     psi(1,j  ) = psi(1,j  ) + coeffy_u
     chi(1,j+1) = chi(1,j+1) + coeffx_u
     chi(1,j-1) = chi(1,j-1) - coeffx_u

  end do

!    [3.2] Eastern boundaries:

  do i = 2,nlat-1
     coeffy_u = coeffy(i,nlon) * u(i,nlon)
     coeffx_u = coeffx(i,nlon) * u(i,nlon)
     coeffy_v = coeffy(i,nlon) * v(i,nlon)
     coeffx_v = coeffx(i,nlon) * v(i,nlon)

     psi(i  ,nlon  ) = psi(i  ,nlon  ) + coeffx_v
     psi(i  ,nlon-2) = psi(i  ,nlon-2) - coeffx_v
     chi(i+1,nlon  ) = chi(i+1,nlon  ) + coeffy_v
     chi(i-1,nlon  ) = chi(i-1,nlon  ) - coeffy_v

     psi(i+1,nlon  ) = psi(i+1,nlon  ) - coeffy_u
     psi(i-1,nlon  ) = psi(i-1,nlon  ) + coeffy_u
     chi(i  ,nlon  ) = chi(i  ,nlon  ) + coeffx_u
     chi(i  ,nlon-2) = chi(i  ,nlon-2) - coeffx_u

  end do

!    [3.1] Western boundaries:

  do i = 2,nlat-1
     coeffy_u = coeffy(i,1) * u(i,1)
     coeffx_u = coeffx(i,1) * u(i,1)
     coeffy_v = coeffy(i,1) * v(i,1)
     coeffx_v = coeffx(i,1) * v(i,1)

     psi(i  ,3) = psi(i  ,3) + coeffx_v
     psi(i  ,1) = psi(i  ,1) - coeffx_v
     chi(i+1,1) = chi(i+1,1) + coeffy_v
     chi(i-1,1) = chi(i-1,1) - coeffy_v

     psi(i+1,1) = psi(i+1,1) - coeffy_u
     psi(i-1,1) = psi(i-1,1) + coeffy_u
     chi(i  ,3) = chi(i  ,3) + coeffx_u
     chi(i  ,1) = chi(i  ,1) - coeffx_u

  end do

!------------------------------------------------------------------------------
!  [2.0] Compute u, v at interior points (2nd order central finite diffs):
!------------------------------------------------------------------------------

  do j = 2,nlon-1
     do i = 2,nlat-1
        coeffy_u = coeffy(i,j) * u(i,j)
        coeffx_u = coeffx(i,j) * u(i,j)
        coeffy_v = coeffy(i,j) * v(i,j)
        coeffx_v = coeffx(i,j) * v(i,j)

        psi(i+1,j  ) = psi(i+1,j   ) - coeffy_u
        psi(i-1,j  ) = psi(i-1,j   ) + coeffy_u
        chi(i  ,j+1) = chi(i  ,j+1) + coeffx_u
        chi(i  ,j-1) = chi(i  ,j-1) - coeffx_u

        psi(i  ,j+1) = psi(i  ,j+1) + coeffx_v
        psi(i  ,j-1) = psi(i  ,j-1) - coeffx_v
        chi(i+1,j  ) = chi(i+1,j  ) + coeffy_v
        chi(i-1,j  ) = chi(i-1,j  ) - coeffy_v

     end do
  end do

end subroutine psichi2uvt_reg

subroutine tdelx_reg( u,  chi,vector)
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    psichi2uvt_reg
!     prgmmr:    barker, d   org:  np22              date:  2000-02-03
!
! abstract:  Calculate adjoint of psi and chi from adjoint of
!            wind components u and v.
!
! program history log:
!   2000/02/03   barker, dale - creation of F90 version
!   2001/10/30   barker       - parallel version
!   2003/09/05   parrish      - adapted to unified NCEP 3dvar
!   2003/10/17   wu, wanshu   - first index Y second X
!   2004-06-22   treadon      - update documentation
!   2009-04-19   derber       - modify to fit gsi
!
!   input argument list:
!     u - adjoint of zonal wind component
!     vector
!
!   output argument list:
!     chi - adjoint of x derivative
!
! remarks:
!    The method used is
!
!    The assumptions made in this routine are:
!       - unstaggered grid,
!       - lateral boundary conditions - dchi/dn = 0 (FCT)
!       - dy=rearth*dph , dx=cos(ph)*rearth*dlm (dx,dy is rotated grid)
!
! attributes:
!   language: f90
!   machine:  ibm rs/6000 sp
!
!$$$
  use kinds, only: r_kind,i_kind
  use constants, only: zero,half
  use gridmod, only: coeffx,nlat,nlon,region_dy,region_dyi
  implicit none

  logical     ,intent(in   ) :: vector
  real(r_kind),intent(inout) :: u(nlat,nlon)   ! u wind comp (m/s)
  real(r_kind),intent(inout) :: chi(nlat,nlon) ! Velocity potential

  integer(i_kind)            :: i, j           ! Loop counters.
  real(r_kind)               :: coeffx_u       ! Multiplicative coefficient.
  real(r_kind)               :: ch2(nlat,nlon)
  real(r_kind)               :: u2(nlat,nlon)

  if(vector) then
     do j=1,nlon
        do i=1,nlat
           u2(i,j)=u(i,j)*region_dyi(i,j)
        end do
     end do
  else
     do j=1,nlon
        do i=1,nlat
           u2(i,j)=u(i,j)
        end do
     end do
  end if

!------------------------------------------------------------------------------
!     [4.0] Corner points (assume average of surrounding points - poor?):
!------------------------------------------------------------------------------

!    [4.1] Bottom-left point:

  u2(2,1) = u2(2,1) + half * u2(1,1)
  u2(1,2) = u2(1,2) + half * u2(1,1)
  u2(1,1) = zero

!    [4.2] Top-left point:

  u2(nlat-1,1) = u2(nlat-1,1) + half * u2(nlat,1)
  u2(nlat  ,2) = u2(nlat  ,2) + half * u2(nlat,1)
  u2(nlat  ,1) = zero

!    [4.3] Bottom-right point:

  u2(2,nlon  ) = u2(2,nlon  ) + half * u2(1,nlon)
  u2(1,nlon-1) = u2(1,nlon-1) + half * u2(1,nlon)
  u2(1,nlon)   = zero

!    [4.4] Top-right point:

  u2(nlat-1,nlon  ) = u2(nlat-1,nlon  ) + half * u2(nlat,nlon)
  u2(nlat  ,nlon-1) = u2(nlat  ,nlon-1) + half * u2(nlat,nlon)
  u2(nlat,nlon)=zero

  ch2=zero

!------------------------------------------------------------------------------
! [3.0] Compute u at domain boundaries:
!------------------------------------------------------------------------------

!    [3.2] Eastern boundaries:

  j = nlon

  do i = 1,nlat
     coeffx_u = coeffx(i,j) * u2(i,j)

     ch2(i,j  ) = ch2(i,j  ) + coeffx_u
     ch2(i,j-2) = ch2(i,j-2) - coeffx_u

  end do

!    [3.1] Western boundaries:
  j = 1

  do i = 1,nlat
     coeffx_u = coeffx(i,j) * u2(i,j)

     ch2(i,j+2) = ch2(i,j+2) + coeffx_u
     ch2(i,j  ) = ch2(i,j  ) - coeffx_u

  end do

!------------------------------------------------------------------------------
!  [2.0] Compute u, v at interior points (2nd order central finite diffs):
!------------------------------------------------------------------------------

  do j = 2,nlon-1
     do i = 1,nlat
        coeffx_u = coeffx(i,j) * u2(i,j)

        ch2(i,j+1) = ch2(i,j+1) + coeffx_u
        ch2(i,j-1) = ch2(i,j-1) - coeffx_u

     end do
  end do

  if(vector) then
     do j=1,nlon
        do i=1,nlat
           chi(i,j)=chi(i,j)+ch2(i,j)*region_dy(i,j)
        end do
     end do
  else
     do j=1,nlon
        do i=1,nlat
           chi(i,j)=chi(i,j)+ch2(i,j)
        end do
     end do
  end if

end subroutine tdelx_reg

subroutine tdely_reg( v,  chi,vector)
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    psichi2uvt_reg
!     prgmmr:    barker, d   org:  np22              date:  2000-02-03
!
! abstract:  Calculate adjoint of psi and chi from adjoint of
!            wind components u and v.
!
! program history log:
!   2000/02/03   barker, dale - creation of F90 version
!   2001/10/30   barker       - parallel version
!   2003/09/05   parrish      - adapted to unified NCEP 3dvar
!   2003/10/17   wu, wanshu   - first index Y second X
!   2004-06-22   treadon      - update documentation
!   2005-09-28   parrish      - fix bug in computing derivatives
!                               along western boundaries
!   2009-04-19   derber       - modify to fit gsi
!
!   input argument list:
!     v - adjoint of meridional wind component
!     vector
!
!   output argument list:
!     chi - adjoint of y derivative
!
! remarks:
!    The method used is
!       v = (  dchi/dy )
!
!    The assumptions made in this routine are:
!       - unstaggered grid,
!       - lateral boundary conditions - dpsi/dn, dchi/dn = 0 (FCT)
!       - dy=rearth*dph , dx=cos(ph)*rearth*dlm (dx,dy is rotated grid)
!
! attributes:
!   language: f90
!   machine:  ibm rs/6000 sp
!
!$$$
  use kinds, only: r_kind,i_kind
  use constants, only: zero,half
  use gridmod, only: coeffy,nlat,nlon,region_dx,region_dxi
  implicit none

  logical     ,intent(in   ) :: vector
  real(r_kind),intent(inout) :: v(nlat,nlon)   ! v wind comp (m/s)
  real(r_kind),intent(inout) :: chi(nlat,nlon) ! Velocity potential

  integer(i_kind)           :: i, j                       ! Loop counters.
  real(r_kind)              :: coeffy_v                   ! Multiplicative coefficient.
  real(r_kind)              :: ch2(nlat,nlon)
  real(r_kind)              :: v2(nlat,nlon)

  if(vector) then
     do j=1,nlon
        do i=1,nlat
           v2(i,j)=v(i,j)*region_dxi(i,j)
        end do
     end do
  else
     do j=1,nlon
        do i=1,nlat
           v2(i,j)=v(i,j)
        end do
     end do
  end if

!------------------------------------------------------------------------------
!     [4.0] Corner points (assume average of surrounding points - poor?):
!------------------------------------------------------------------------------

!    [4.1] Bottom-left point:

  v2(2,1) = v2(2,1) + half * v2(1,1)
  v2(1,2) = v2(1,2) + half * v2(1,1)
  v2(1,1) = zero

!    [4.2] Top-left point:

  v2(nlat-1,1) = v2(nlat-1,1) + half * v2(nlat,1)
  v2(nlat  ,2) = v2(nlat  ,2) + half * v2(nlat,1)
  v2(nlat,1)      = zero

!    [4.3] Bottom-right point:

  v2(2,nlon  ) = v2(2,nlon  ) + half * v2(1,nlon)
  v2(1,nlon-1) = v2(1,nlon-1) + half * v2(1,nlon)
  v2(1,nlon  ) = zero

!    [4.4] Top-right point:

  v2(nlat-1,nlon  ) = v2(nlat-1,nlon  ) + half * v2(nlat,nlon)
  v2(nlat  ,nlon-1) = v2(nlat  ,nlon-1) + half * v2(nlat,nlon)
  v2(nlat  ,nlon  ) = zero

!------------------------------------------------------------------------------
! [3.0] Compute u, v at domain boundaries:
!------------------------------------------------------------------------------

  ch2=zero

  i=nlat
  do j = 1,nlon
     coeffy_v = coeffy(i,j) * v2(i,j)

     ch2(i  ,j) = ch2(i  ,j) + coeffy_v
     ch2(i-2,j) = ch2(i-2,j) - coeffy_v

  end do

!    [3.3] Southern boundaries:

  i = 1

  do j = 1,nlon
     coeffy_v = coeffy(i,j) * v2(i,j)

     ch2(i+2,j) = ch2(i+2,j) + coeffy_v
     ch2(i  ,j) = ch2(i  ,j) - coeffy_v

  end do

!------------------------------------------------------------------------------
!  [2.0] Compute u, v at interior points (2nd order central finite diffs):
!------------------------------------------------------------------------------

  do j = 1,nlon
     do i = 2,nlat-1
        coeffy_v = coeffy(i,j) * v2(i,j)

        ch2(i+1,j) = ch2(i+1,j) + coeffy_v
        ch2(i-1,j) = ch2(i-1,j) - coeffy_v

     end do
  end do

  if(vector) then
     do j=1,nlon
        do i=1,nlat
           chi(i,j)=chi(i,j)+ch2(i,j)*region_dx(i,j)
        end do
     end do
  else
     do j=1,nlon
        do i=1,nlat
           chi(i,j)=chi(i,j)+ch2(i,j)
        end do
     end do
  end if

end subroutine tdely_reg