module intbendmod 2

!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    intbendmod    module for intbend and its tangent linear intbend_tl
!
! abstract: module for intbend and its tangent linear intbend_tl
!
! program history log:
!   2005-12-02 cucurull 
!

implicit none

PRIVATE
PUBLIC intbend,intbend_tl

contains


subroutine intbend(rt,rq,rp,st,sq,sp) 1,12
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    intbend      apply nonlinqc obs operator for GPS bending angle 
!   prgmmr: cucurull, l.     org: JCSDA/NCEP          date: 2005-12-02
!
! abstract: apply gps bending angle operator and adjoint with
!           addition of nonlinear qc.
!
! program history log:
!   2004-04-29  cucurull- original code
!   2006-03-07  todling - bug fix: nsig_up was declared as real
!   2006-07-28  derber  - modify to use new inner loop obs data structure
!                       - unify NL qc
!   
!   input argument list:
!     st       - input temperature correction field
!     sq       - input q correction field
!     sp       - input p correction field
!
!   output argument list:
!     rt       - output vector after inclusion of gps bending angle
!     rq       - output q vector after inclusion of gps bending angle
!     rp       - output p vector after inclusion of gps bending angle
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
  use kinds, only: r_kind,i_kind
  use obsmod, only: gpshead,gpsptr,grids_dim
  use qcmod, only: nlnqc_iter
  use gridmod, only: latlon1n,latlon11,nsig
  use lagmod
  use jfunc, only: jiter,iter
  use constants, only: zero,one,two,n_a,n_b,grav,rd,half,tiny_r_kind,cg_term
  implicit none

! Declare local parameters
  real(r_kind),parameter:: ten = 10.0_r_kind
  real(r_kind),parameter:: ds=5000.0_r_kind
  real(r_kind),parameter:: r1em6=1.0e-6_r_kind

! Declare passed variables
  real(r_kind),dimension(latlon1n),intent(in):: st,sq
  real(r_kind),dimension(latlon1n),intent(inout):: rt,rq
  real(r_kind),dimension(latlon11),intent(in):: sp
  real(r_kind),dimension(latlon11),intent(inout):: rp


! Declare local variables
  integer(i_kind) i,j,k,ihob,nsig_up
  integer(i_kind),dimension(nsig):: i1,i2,i3,i4
! real(r_kind) penalty
  real(r_kind) w1_gps,w2_gps,w3_gps,w4_gps
  real(r_kind) :: p_TL,p_AD
  real(r_kind),dimension(nsig) :: q_TL,t_TL,q_AD,t_AD
  real(r_kind) :: val
  real(r_kind) cg_gps,grad,p0,wnotgross,wgross

  real(r_kind) ddbend,dz,rdog,rsig,h,hob_s,d_ref_rad_TL,d_ref_rad
  real(r_kind) dbend_AD,ddbend_AD,d_ref_rad_AD
  real(r_kind),dimension(nsig) :: irefges,height_TL,h_TL,height_AD,h_AD,hk_AD,dz_AD
  real(r_kind),dimension(3,nsig+6) :: q_w,q_w_TL,q_w_AD
  real(r_kind),dimension(4) :: dw4_TL,w4,dw4,w4_TL,w4_AD,dw4_AD
  real(r_kind),dimension(grids_dim) :: dbeta_TL,dbeta_AD
  real(r_kind),dimension(nsig+6) :: n_TL,n_AD
  real(r_kind),dimension(0:nsig+7) ::  ref_rad,xi_TL,xi_AD

! Loop over observations

  gpsptr => gpshead
  do while (associated(gpsptr))

! Load location information into local variables
    do j=1,nsig
      i1(j)= gpsptr%ij(1,j)
      i2(j)= gpsptr%ij(2,j)
      i3(j)= gpsptr%ij(3,j)
      i4(j)= gpsptr%ij(4,j)
    enddo
    w1_gps=gpsptr%wij(1)
    w2_gps=gpsptr%wij(2)
    w3_gps=gpsptr%wij(3)
    w4_gps=gpsptr%wij(4)

!   increments

    p_TL=w1_gps*sp(i1(1))+w2_gps*sp(i2(1))+w3_gps*sp(i3(1))&
        +w4_gps*sp(i4(1))

    do j=1,nsig
      t_TL(j)=w1_gps*st(i1(j))+w2_gps*st(i2(j))+w3_gps*st(i3(j))&
             +w4_gps*st(i4(j))
      q_TL(j)=w1_gps*sq(i1(j))+w2_gps*sq(i2(j))+w3_gps*sq(i3(j))&
             +w4_gps*sq(i4(j))
    enddo


!   local bending angle

!   Initialize some arrays
    h_TL=zero;n_TL=zero;xi_TL=zero
    d_ref_rad_TL=zero; dbeta_TL=zero
    q_w_TL=zero;w4_TL=zero;dw4_TL=zero ! Lagrange weights

    nsig_up=nsig+6 ! extend levels
    rsig=float(nsig)

!   Geopotential heights
    rdog = rd/grav
    k  = 1
    h  = rdog * t_TL(k)
    dz = h * (gpsptr%b_psges-gpsptr%b_pkges(k))
    height_TL(k) = dz
    do k=2,nsig
      h  = rdog * half * (t_TL(k-1)+t_TL(k))
      dz = h * (gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
      height_TL(k) = height_TL(k-1) + dz
    end do
    do k=1,nsig
      h_TL(k)=height_TL(k)
    end do

!   Increment of refractivity and index of refractivity - radius product
    do k=1,nsig
      irefges(k)= one+(r1em6*gpsptr%b_n(k))  ! index of refractivity
      ref_rad(k)=irefges(k)*gpsptr%b_rges(k) ! refractivity index-radius product
      n_TL(k)=gpsptr%b_tin(k)*t_TL(k)+gpsptr%b_qin(k)*q_TL(k)+ &
              gpsptr%b_pin(k)*p_TL
       xi_TL(k)=r1em6*gpsptr%b_rges(k)*n_TL(k)+ &
                      gpsptr%b_gp2gm(k)*h_TL(k)*irefges(k)
    end do

!   Extending atmosphere above nsig
    d_ref_rad=ref_rad(nsig)-ref_rad(nsig-1)
    d_ref_rad_TL=xi_TL(nsig)-xi_TL(nsig-1)
    do k=1,6
      ref_rad(nsig+k)=ref_rad(nsig)+ k*d_ref_rad
      xi_TL(nsig+k)=xi_TL(nsig)+ k*d_ref_rad_TL
      n_TL(nsig+k)=(two*gpsptr%b_n(nsig+k-1)*n_TL(nsig+k-1)/gpsptr%b_n(nsig+k-2))-&
               (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_TL(nsig+k-2)
    end do

!   Lagrange coefficients
    ref_rad(0)=ref_rad(3)
    ref_rad(nsig_up+1)=ref_rad(nsig_up-2)
    xi_TL(0)=xi_TL(3)
    xi_TL(nsig_up+1)=xi_TL(nsig_up-2)
    do k=1,nsig_up
      call setq_TL(q_w(:,k),q_w_TL(:,k),ref_rad(k-1:k+1),xi_TL(k-1:k+1),3)
    enddo
!
    intloop: do j=1,grids_dim
      hob_s=gpsptr%b_loc(j)
      ihob=hob_s
      w4_TL=zero;dw4_TL=zero

!   Compute refractivity and derivative at target points using Lagrange interpolators
      call slagdw_TL(ref_rad(ihob-1:ihob+2),xi_TL(ihob-1:ihob+2),&
                 gpsptr%b_xj(j),&
                 q_w(:,ihob),q_w_TL(:,ihob),&
                 q_w(:,ihob+1),q_w_TL(:,ihob+1),&
                 w4_TL,dw4,dw4_TL,4)
      if(ihob==1) then
        dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=zero
        dw4_TL(4)=dw4_TL(4)+dw4_TL(1);dw4_TL(1:3)=dw4_TL(2:4);dw4_TL(4)=zero
        ihob=ihob+1
      endif
      if(ihob==nsig_up-1) then
        dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=zero
        dw4_TL(1)=dw4_TL(1)+dw4_TL(4); dw4_TL(2:4)=dw4_TL(1:3);dw4_TL(1)=zero
        ihob=ihob-1
      endif
      dbeta_TL(j)=(r1em6/gpsptr%b_xj(j))*&
        (dot_product(dw4_TL,gpsptr%b_n(ihob-1:ihob+2))+&
         dot_product(dw4,n_TL(ihob-1:ihob+2)))
    end do intloop

    val=ds*dbeta_TL(1)
    do j=2,grids_dim
       ddbend=ds*dbeta_TL(j)
       val=val+two*ddbend
    end do
    val=-gpsptr%b_imp*val

    val=val-gpsptr%res

!   needed for gradient of nonlinear qc operator
    if (nlnqc_iter .and. gpsptr%pg > tiny_r_kind .and. &
                         gpsptr%b  > tiny_r_kind) then
       cg_gps=cg_term/gpsptr%b
       wnotgross= one-gpsptr%pg
       wgross = gpsptr%pg*cg_gps/wnotgross
       p0   = wgross/(wgross+exp(-half*gpsptr%err2*val**2))
       val = val*(one-p0)
    endif

    grad     = val*gpsptr%raterr2*gpsptr%err2

!   adjoint 

!   Initialize (profile dependendant) adjoint variables
    n_AD=zero;q_w_AD=zero;xi_AD=zero
    h_AD=zero
    q_AD=zero;p_AD=zero;t_AD=zero ! model terms

!   initialize obs dependent adjoint variables
    dbend_AD=zero;ddbend_AD=zero;dbeta_AD=zero 

    dbend_AD=dbend_AD-gpsptr%b_imp*grad
    do j=2,grids_dim  
       ddbend_AD=2*dbend_AD
       dbeta_AD(j)=dbeta_AD(j)+ds*ddbend_AD
    enddo
    dbeta_AD(1)=dbeta_AD(1)+ds*dbend_AD

    do j=grids_dim,1,-1
      w4_AD=zero;dw4_AD=zero
      hob_s=gpsptr%b_loc(j)
      ihob=hob_s
!
      call slagdw(ref_rad(ihob-1:ihob+2),gpsptr%b_xj(j),&
                   q_w(:,ihob),q_w(:,ihob+1),&
                   w4,dw4,4)
      if(ihob==1) then
         dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=zero
         ihob=ihob+1
      endif
      if(ihob==nsig_up-1) then
         dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=zero
         ihob=ihob-1
      endif

      dw4_AD(1)=dw4_AD(1)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob-1)
      dw4_AD(2)=dw4_AD(2)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob)
      dw4_AD(3)=dw4_AD(3)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob+1)
      dw4_AD(4)=dw4_AD(4)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob+2)
!
      n_AD(ihob-1)=n_AD(ihob-1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(1)*dbeta_AD(j)
      n_AD(ihob)  =n_AD(ihob)  +&
                      (r1em6/gpsptr%b_xj(j))*dw4(2)*dbeta_AD(j)
      n_AD(ihob+1)=n_AD(ihob+1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(3)*dbeta_AD(j)
      n_AD(ihob+2)=n_AD(ihob+2)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(4)*dbeta_AD(j)
!
      if(int(hob_s)==nsig_up-1) then
       ihob=ihob+1
       dw4_AD(1:3)=dw4_AD(2:4)
       dw4_AD(4)=dw4_AD(1)
      endif
      if(int(hob_s)==1) then
        ihob=ihob-1
        dw4_AD(2:4)=dw4_AD(1:3)
        dw4_AD(1)=dw4_AD(4)
      endif

!     Compute refractivity and derivative at target points using Lagrange interpolators
      call slagdw_AD(ref_rad(ihob-1:ihob+2),xi_AD(ihob-1:ihob+2),&
          gpsptr%b_xj(j),&
          q_w(:,ihob),q_w_AD(:,ihob),&
          q_w(:,ihob+1),q_w_AD(:,ihob+1),&
          w4_AD,dw4,dw4_AD,4)
    end do ! grids dim

!   Lagrange coefficients
    do k=nsig_up,1,-1
      call setq_AD(q_w_AD(:,k),ref_rad(k-1:k+1),xi_AD(k-1:k+1),3)
    enddo
    xi_AD(nsig_up-2)=xi_AD(nsig_up-2)+xi_AD(nsig_up+1)
    xi_AD(3)=xi_AD(3)+xi_AD(0)

!   Extending atmosphere above nsig
    d_ref_rad_AD=zero
    do k=6,1,-1
      n_AD(nsig+k-1)=n_AD(nsig+k-1)+&
                     n_AD(nsig+k)*two*gpsptr%b_n(nsig+k-1)/gpsptr%b_n(nsig+k-2)
      n_AD(nsig+k-2)=n_AD(nsig+k-2)-&
                     (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_AD(nsig+k)
      xi_AD(nsig)=xi_AD(nsig)+xi_AD(nsig+k)
      d_ref_rad_AD=d_ref_rad_AD+k*xi_AD(nsig+k)
    end do
    xi_AD(nsig)=xi_AD(nsig)+d_ref_rad_AD
    xi_AD(nsig-1)=xi_AD(nsig-1)-d_ref_rad_AD

!   Increment of refractivity and index of refractivity - radius product
    do k=1,nsig
      n_AD(k)=n_AD(k)+r1em6*gpsptr%b_rges(k)*xi_AD(k)
      h_AD(k)=h_AD(k)+gpsptr%b_gp2gm(k)*irefges(k)*xi_AD(k)
      t_AD(k)=t_AD(k)+gpsptr%b_tin(k)*n_AD(k)
      q_AD(k)=q_AD(k)+gpsptr%b_qin(k)*n_AD(k)
      p_AD=p_AD+gpsptr%b_pin(k)*n_AD(k)
    end do

!   geopotential heights
    height_AD=zero;dz_AD=zero;hk_AD=zero
    do k=1,nsig
       height_AD(k)=height_AD(k)+h_AD(k)
    end do
    do k=nsig,2,-1
      height_AD(k-1)=height_AD(k-1)+height_AD(k)
      dz_AD(k)=dz_AD(k)+height_AD(k)
      hk_AD(k)=hk_AD(k)+dz_AD(k)*(gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
      t_AD(k-1) = t_AD(k-1)+rdog*half*hk_AD(k)
      t_AD(k)   = t_AD(k)+rdog*half*hk_AD(k)
    end do
    dz_AD(1)=dz_AD(1)+height_AD(1)
    hk_AD(1)=hk_AD(1)+dz_AD(1)*(gpsptr%b_psges-gpsptr%b_pkges(1))
    t_AD(1)=t_AD(1)+ hk_AD(1)*rdog

!   Interpolation

    do j=1,nsig
      rt(i1(j))=rt(i1(j))+w1_gps*t_AD(j)
      rt(i2(j))=rt(i2(j))+w2_gps*t_AD(j)
      rt(i3(j))=rt(i3(j))+w3_gps*t_AD(j)
      rt(i4(j))=rt(i4(j))+w4_gps*t_AD(j)

      rq(i1(j))=rq(i1(j))+w1_gps*q_AD(j)
      rq(i2(j))=rq(i2(j))+w2_gps*q_AD(j)
      rq(i3(j))=rq(i3(j))+w3_gps*q_AD(j)
      rq(i4(j))=rq(i4(j))+w4_gps*q_AD(j)
    enddo

    rp(i1(1))=rp(i1(1))+w1_gps*p_AD
    rp(i2(1))=rp(i2(1))+w2_gps*p_AD
    rp(i3(1))=rp(i3(1))+w3_gps*p_AD
    rp(i4(1))=rp(i4(1))+w4_gps*p_AD

    gpsptr => gpsptr%llpoint

  end do

  return
end subroutine intbend



subroutine intbend_tl(rt,rq,rp,st,sq,sp,rt_tl,rq_tl,rp_tl,st_tl,sq_tl,sp_tl) 1,16
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    intbend_tl     the tangent linear of the operator that applies 
!                               nonlinqc obs operator local bending angle
!   prgmmr: cucurull    org: JCSDA/NCEP          date: 2005-12-02
!
! abstract: the tangent linear of the operator that applies gps local 
!           bending angle operator and adjoint with addition of nonlinear qc.
!
! program history log:
!   2005-12-02  cucurull - tangent linear of intbend
!   2006-03-07  todling  - bug fix: nsig_up was declared as real
!   
!   input argument list:
!     st       - input temperature correction field
!     sq       - input q correction field
!     sp       - input p correction field
!     st_tl     - input tangent linear temperature correction field
!     sq_tl     - input tangent linear q correction field
!     sp_tl     - input tangent linear p correction field
!
!   output argument list:
!     rt       - output vector after inclusion of gps bending angle
!     rq       - output q vector after inclusion of gps bending angle
!     rp       - output p vector after inclusion of gps bending angle
!     rt_tl     - output tangent linear vector after inclusion of gps bending angle
!     rq_tl     - output tangent linear q vector after inclusion of gps bending angle
!     rp_tl     - output tangent linear p vector after inclusion of gps bending angle
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
  use kinds, only: r_kind,i_kind
  use obsmod, only: gpshead,gpsptr,grids_dim
  use obsmod_tl, only: gpsdataerr_tl
  use qcmod, only: nlnqc_iter
  use gridmod, only: latlon1n,latlon11,nsig
  use lagmod
  use constants, only: zero,one,two,n_a,n_b,grav,rd,half,tiny_r_kind,cg_term
  implicit none

! Declare local parameters
  real(r_kind),parameter:: ten = 10.0_r_kind
  real(r_kind),parameter:: ds=5000.0_r_kind
  real(r_kind),parameter:: r1em6=1.0e-6_r_kind

! Declare passed variables
  real(r_kind),dimension(latlon1n),intent(in):: st,sq
  real(r_kind),dimension(latlon1n),intent(in):: st_tl,sq_tl
  real(r_kind),dimension(latlon1n),intent(inout):: rt,rq
  real(r_kind),dimension(latlon1n),intent(inout):: rt_tl,rq_tl
  real(r_kind),dimension(latlon11),intent(in):: sp,sp_tl
  real(r_kind),dimension(latlon11),intent(inout):: rp,rp_tl


! Declare local variables
  integer(i_kind) i,j,k,ihob,nsig_up
  integer(i_kind),dimension(nsig):: i1,i2,i3,i4
! real(r_kind) penalty
  real(r_kind) w1_gps,w2_gps,w3_gps,w4_gps
  real(r_kind) :: p_TL,p_AD
  real(r_kind),dimension(nsig) :: q_TL,t_TL,q_AD,t_AD
  real(r_kind) :: p_TL_tl,p_AD_tl
  real(r_kind),dimension(nsig) :: q_TL_tl,t_TL_tl,q_AD_tl,t_AD_tl
  real(r_kind) :: val
  real(r_kind) :: val_tl
  real(r_kind) cg_gps,grad,p0,wnotgross,wgross,term
  real(r_kind) grad_tl,p0_tl,term_tl

  real(r_kind) ddbend,dz,rdog,rsig,h,hob_s,d_ref_rad_TL,d_ref_rad
  real(r_kind) dbend_AD,ddbend_AD,d_ref_rad_AD
  real(r_kind),dimension(nsig) :: irefges,height_TL,h_TL,height_AD,h_AD,hk_AD,dz_AD
  real(r_kind),dimension(3,nsig+6) :: q_w,q_w_TL,q_w_AD
  real(r_kind),dimension(4) :: dw4_TL,w4,dw4,w4_TL,w4_AD,dw4_AD
  real(r_kind),dimension(grids_dim) :: dbeta_TL,dbeta_AD
  real(r_kind),dimension(nsig+6) :: n_TL,n_AD
  real(r_kind),dimension(0:nsig+7) ::  ref_rad,xi_TL,xi_AD

  real(r_kind) d_ref_rad_TL_tl
  real(r_kind) dbend_AD_tl,ddbend_AD_tl,d_ref_rad_AD_tl
  real(r_kind),dimension(nsig) :: height_TL_tl,h_TL_tl,height_AD_tl
  real(r_kind),dimension(nsig) :: h_AD_tl,hk_AD_tl,dz_AD_tl
  real(r_kind),dimension(3,nsig+6) :: q_w_TL_tl,q_w_AD_tl
  real(r_kind),dimension(4) :: dw4_TL_tl,w4_TL_tl,w4_AD_tl,dw4_AD_tl
  real(r_kind),dimension(grids_dim) :: dbeta_TL_tl,dbeta_AD_tl
  real(r_kind),dimension(nsig+6) :: n_TL_tl,n_AD_tl
  real(r_kind),dimension(0:nsig+7) ::  xi_TL_tl,xi_AD_tl


! Loop over observations
  gpsptr => gpshead
  do while (associated(gpsptr))

! Load location information into local variables
   do j=1,nsig
    i1(j)= gpsptr%ij(1,j)
    i2(j)= gpsptr%ij(2,j)
    i3(j)= gpsptr%ij(3,j)
    i4(j)= gpsptr%ij(4,j)
   enddo
   w1_gps=gpsptr%wij(1)
   w2_gps=gpsptr%wij(2)
   w3_gps=gpsptr%wij(3)
   w4_gps=gpsptr%wij(4)

! increments

  p_TL=w1_gps*sp(i1(1))+w2_gps*sp(i2(1))+w3_gps*sp(i3(1))&
       +w4_gps*sp(i4(1))
  p_TL_tl=w1_gps*sp_tl(i1(1))+w2_gps*sp_tl(i2(1))+w3_gps*sp_tl(i3(1))&
       +w4_gps*sp_tl(i4(1))

  do j=1,nsig
   t_TL(j)=w1_gps*st(i1(j))+w2_gps*st(i2(j))+w3_gps*st(i3(j))&
            +w4_gps*st(i4(j))
   q_TL(j)=w1_gps*sq(i1(j))+w2_gps*sq(i2(j))+w3_gps*sq(i3(j))&
           +w4_gps*sq(i4(j))
   t_TL_tl(j)=w1_gps*st_tl(i1(j))+w2_gps*st_tl(i2(j))+w3_gps*st_tl(i3(j))&
            +w4_gps*st_tl(i4(j))
   q_TL_tl(j)=w1_gps*sq_tl(i1(j))+w2_gps*sq_tl(i2(j))+w3_gps*sq_tl(i3(j))&
           +w4_gps*sq_tl(i4(j))
  enddo

! Initialize some arrays
  h_TL=zero;n_TL=zero;xi_TL=zero
  d_ref_rad_TL=zero; dbeta_TL=zero
  q_w_TL=zero;w4_TL=zero;dw4_TL=zero ! Lagrange weights

  h_TL_tl=zero;n_TL_tl=zero;xi_TL_tl=zero
  d_ref_rad_TL_tl=zero;dbeta_TL_tl=zero
  q_w_TL_tl=zero;w4_TL_tl=zero;dw4_TL_tl=zero ! Lagrange weights

  nsig_up=nsig+6 ! extend levels
  rsig=float(nsig)

! Geopotential heights
  rdog = rd/grav
  k  = 1
  h  = rdog * t_TL(k)
  dz = h * (gpsptr%b_psges-gpsptr%b_pkges(k))
  height_TL(k) = dz
  do k=2,nsig
     h  = rdog * half * (t_TL(k-1)+t_TL(k))
     dz = h * (gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
     height_TL(k) = height_TL(k-1) + dz
  end do
  do k=1,nsig
     h_TL(k)=height_TL(k)
  end do

  k  = 1
  h  = rdog * t_TL_tl(k)
  dz = h * (gpsptr%b_psges-gpsptr%b_pkges(k))
  height_TL_tl(k) = dz
  do k=2,nsig
     h  = rdog * half * (t_TL_tl(k-1)+t_TL_tl(k))
     dz = h * (gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
     height_TL_tl(k) = height_TL_tl(k-1) + dz
  end do
  do k=1,nsig
     h_TL_tl(k)=height_TL_tl(k)
  end do

! Increment of refractivity and index of refractivity - radius product
  do k=1,nsig
   irefges(k)= one+(r1em6*gpsptr%b_n(k))  ! index of refractivity
   ref_rad(k)=irefges(k)*gpsptr%b_rges(k)               ! refractivity index-radius product
   n_TL(k)=gpsptr%b_tin(k)*t_TL(k)+gpsptr%b_qin(k)*q_TL(k)+ &
           gpsptr%b_pin(k)*p_TL
   xi_TL(k)=r1em6*gpsptr%b_rges(k)*n_TL(k)+ &
                  gpsptr%b_gp2gm(k)*h_TL(k)*irefges(k)
   n_TL_tl(k)=gpsptr%b_tin(k)*t_TL_tl(k)+gpsptr%b_qin(k)*q_TL_tl(k)+ &
              gpsptr%b_pin(k)*p_TL_tl
   xi_TL_tl(k)=r1em6*gpsptr%b_rges(k)*n_TL_tl(k)+ &
                     gpsptr%b_gp2gm(k)*h_TL_tl(k)*irefges(k)
  end do

! Extending atmosphere above nsig
  d_ref_rad=ref_rad(nsig)-ref_rad(nsig-1)
  d_ref_rad_TL=xi_TL(nsig)-xi_TL(nsig-1)
  d_ref_rad_TL_tl=xi_TL_tl(nsig)-xi_TL_tl(nsig-1)
  do k=1,6
   ref_rad(nsig+k)=ref_rad(nsig)+ k*d_ref_rad
   xi_TL(nsig+k)=xi_TL(nsig)+ k*d_ref_rad_TL
   n_TL(nsig+k)=(two*gpsptr%b_n(nsig+k-1)*n_TL(nsig+k-1)/gpsptr%b_n(nsig+k-2))-&
                  (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_TL(nsig+k-2)
   xi_TL_tl(nsig+k)=xi_TL_tl(nsig)+ k*d_ref_rad_TL_tl
   n_TL_tl(nsig+k)=(two*gpsptr%b_n(nsig+k-1)*n_TL_tl(nsig+k-1)/gpsptr%b_n(nsig+k-2))-&
                  (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_TL_tl(nsig+k-2)
  end do

! Lagrange coefficients
  ref_rad(0)=ref_rad(3)
  ref_rad(nsig_up+1)=ref_rad(nsig_up-2)
  xi_TL(0)=xi_TL(3)
  xi_TL(nsig_up+1)=xi_TL(nsig_up-2)
  xi_TL_tl(0)=xi_TL_tl(3)
  xi_TL_tl(nsig_up+1)=xi_TL_tl(nsig_up-2)
  do k=1,nsig_up
   call setq_TL(q_w(:,k),q_w_TL(:,k),ref_rad(k-1:k+1),xi_TL(k-1:k+1),3)
   call setq_TL(q_w(:,k),q_w_TL_tl(:,k),ref_rad(k-1:k+1),xi_TL_tl(k-1:k+1),3) 
  enddo
!
  intloop: do j=1,grids_dim
    hob_s=gpsptr%b_loc(j)
    ihob=hob_s
    w4_TL=zero;dw4_TL=zero
    w4_TL_tl=zero;dw4_TL_tl=zero

! Compute refractivity and derivative at target points using Lagrange interpolators
    call slagdw_TL(ref_rad(ihob-1:ihob+2),xi_TL(ihob-1:ihob+2),&
               gpsptr%b_xj(j),&
               q_w(:,ihob),q_w_TL(:,ihob),&
               q_w(:,ihob+1),q_w_TL(:,ihob+1),&
               w4_TL,dw4,dw4_TL,4)
    call slagdw_TL(ref_rad(ihob-1:ihob+2),xi_TL_tl(ihob-1:ihob+2),&
               gpsptr%b_xj(j),&
               q_w(:,ihob),q_w_TL_tl(:,ihob),&
               q_w(:,ihob+1),q_w_TL_tl(:,ihob+1),&
               w4_TL_tl,dw4,dw4_TL_tl,4)
    if(ihob==1) then
      dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=zero
      dw4_TL(4)=dw4_TL(4)+dw4_TL(1);dw4_TL(1:3)=dw4_TL(2:4);dw4_TL(4)=zero
      dw4_TL_tl(4)=dw4_TL_tl(4)+dw4_TL_tl(1);dw4_TL_tl(1:3)=dw4_TL_tl(2:4);dw4_TL_tl(4)=zero
      ihob=ihob+1
    endif
    if(ihob==nsig_up-1) then
      dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=zero
      dw4_TL(1)=dw4_TL(1)+dw4_TL(4);dw4_TL(2:4)=dw4_TL(1:3);dw4_TL(1)=zero
      dw4_TL_tl(1)=dw4_TL_tl(1)+dw4_TL_tl(4);dw4_TL_tl(2:4)=dw4_TL_tl(1:3);dw4_TL_tl(1)=zero
      ihob=ihob-1
    endif
    dbeta_TL(j)=(r1em6/gpsptr%b_xj(j))*&
      (dot_product(dw4_TL,gpsptr%b_n(ihob-1:ihob+2))+&
       dot_product(dw4,n_TL(ihob-1:ihob+2)))
    dbeta_TL_tl(j)=(r1em6/gpsptr%b_xj(j))*&
      (dot_product(dw4_TL_tl,gpsptr%b_n(ihob-1:ihob+2))+&
       dot_product(dw4,n_TL_tl(ihob-1:ihob+2)))
  end do intloop

  val=ds*dbeta_TL(1)
  do j=2,grids_dim
     ddbend=ds*dbeta_TL(j)
     val=val+two*ddbend
  end do
  val=-gpsptr%b_imp*val
  val=val-gpsptr%res

  val_tl=ds*dbeta_TL_tl(1)
  do j=2,grids_dim
     ddbend=ds*dbeta_TL_tl(j)
     val_tl=val_tl+two*ddbend
  end do
  val_tl=-gpsptr%b_imp*val_tl
  val_tl=val_tl-gpsdataerr_tl(i)

! needed for gradient of nonlinear qc operator
  if (nlnqc_iter .and. gpsptr%pg > tiny_r_kind) then
     cg_gps=cg_term/gpsptr%b
     wnotgross= one-gpsptr%pg
     wgross = gpsptr%pg*cg_gps
     p0   = wnotgross*exp(-half*gpsptr%err2*val**2)+wgross
     term = (p0-wgross)/p0
     p0_tl = -val*(p0-wgross)*val_tl*gpsptr%err2
     term_tl = wgross/(p0*p0)*p0_tl
  else
     term = one
     term_tl = zero
  endif
  grad     = val * term
  grad_tl   = val_tl * term + val * term_tl
  grad     = grad*gpsptr%raterr2*gpsptr%err2
  grad_tl   = grad_tl*gpsptr%raterr2*gpsptr%err2

! adjoint 

! Initialize (profile dependendant) adjoint variables
  n_AD=zero;q_w_AD=zero;xi_AD=zero
  h_AD=zero
  q_AD=zero;p_AD=zero;t_AD=zero ! model terms

  n_AD_tl=zero;q_w_AD_tl=zero;xi_AD_tl=zero
  h_AD_tl=zero
  q_AD_tl=zero;p_AD_tl=zero;t_AD_tl=zero ! model terms

! initialize obs dependent adjoint variables
  dbend_AD=zero;ddbend_AD=zero;dbeta_AD=zero
  dbend_AD_tl=zero;ddbend_AD_tl=zero;dbeta_AD_tl=zero

  dbend_AD=dbend_AD-gpsptr%b_imp*grad
  dbend_AD_tl=dbend_AD_tl-gpsptr%b_imp*grad_tl
  do j=2,grids_dim  ! no reverse order needed
     ddbend_AD=2*dbend_AD
     dbeta_AD(j)=dbeta_AD(j)+ds*ddbend_AD
     ddbend_AD_tl=2*dbend_AD_tl
     dbeta_AD_tl(j)=dbeta_AD_tl(j)+ds*ddbend_AD_tl
  enddo
  dbeta_AD(1)=dbeta_AD(1)+ds*dbend_AD
  dbeta_AD_tl(1)=dbeta_AD_tl(1)+ds*dbend_AD_tl

  do j=grids_dim,1,-1
    w4_AD=zero;dw4_AD=zero
    w4_AD_tl=zero;dw4_AD_tl=zero
    hob_s=gpsptr%b_loc(j)
    ihob=hob_s
!
    call slagdw(ref_rad(ihob-1:ihob+2),gpsptr%b_xj(j),&
                   q_w(:,ihob),q_w(:,ihob+1),&
                   w4,dw4,4)
    if(ihob==1) then
       dw4(4)=dw4(4)+dw4(1);dw4(1:3)=dw4(2:4);dw4(4)=zero
       ihob=ihob+1
    endif
    if(ihob==nsig_up-1) then
       dw4(1)=dw4(1)+dw4(4); dw4(2:4)=dw4(1:3);dw4(1)=zero
       ihob=ihob-1
    endif

    dw4_AD(1)=dw4_AD(1)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob-1)
    dw4_AD(2)=dw4_AD(2)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob)
    dw4_AD(3)=dw4_AD(3)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob+1)
    dw4_AD(4)=dw4_AD(4)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD(j)*gpsptr%b_n(ihob+2)
    dw4_AD_tl(1)=dw4_AD_tl(1)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD_tl(j)*gpsptr%b_n(ihob-1)
    dw4_AD_tl(2)=dw4_AD_tl(2)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD_tl(j)*gpsptr%b_n(ihob)
    dw4_AD_tl(3)=dw4_AD_tl(3)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD_tl(j)*gpsptr%b_n(ihob+1)
    dw4_AD_tl(4)=dw4_AD_tl(4)+&
                (r1em6/gpsptr%b_xj(j))*dbeta_AD_tl(j)*gpsptr%b_n(ihob+2)

    n_AD(ihob-1)=n_AD(ihob-1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(1)*dbeta_AD(j)
    n_AD(ihob)  =n_AD(ihob)  +&
                      (r1em6/gpsptr%b_xj(j))*dw4(2)*dbeta_AD(j)
    n_AD(ihob+1)=n_AD(ihob+1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(3)*dbeta_AD(j)
    n_AD(ihob+2)=n_AD(ihob+2)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(4)*dbeta_AD(j)
    n_AD_tl(ihob-1)=n_AD_tl(ihob-1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(1)*dbeta_AD_tl(j)
    n_AD_tl(ihob)  =n_AD_tl(ihob)  +&
                      (r1em6/gpsptr%b_xj(j))*dw4(2)*dbeta_AD_tl(j)
    n_AD_tl(ihob+1)=n_AD_tl(ihob+1)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(3)*dbeta_AD_tl(j)
    n_AD_tl(ihob+2)=n_AD_tl(ihob+2)+&
                      (r1em6/gpsptr%b_xj(j))*dw4(4)*dbeta_AD_tl(j)
!
   if(int(hob_s)==nsig_up-1) then
    ihob=ihob+1
    dw4_AD(1:3)=dw4_AD(2:4)
    dw4_AD(4)=dw4_AD(1)
    dw4_AD_tl(1:3)=dw4_AD_tl(2:4)
    dw4_AD_tl(4)=dw4_AD_tl(1)
   endif
   if(int(hob_s)==1) then
    ihob=ihob-1
    dw4_AD(2:4)=dw4_AD(1:3)
    dw4_AD(1)=dw4_AD(4)
    dw4_AD_tl(2:4)=dw4_AD_tl(1:3)
    dw4_AD_tl(1)=dw4_AD_tl(4)
   endif

! Compute refractivity and derivative at target points using Lagrange interpolators
    call slagdw_AD(ref_rad(ihob-1:ihob+2),xi_AD(ihob-1:ihob+2),&
         gpsptr%b_xj(j),&
         q_w(:,ihob),q_w_AD(:,ihob),&
         q_w(:,ihob+1),q_w_AD(:,ihob+1),&
         w4_AD,dw4,dw4_AD,4)
    call slagdw_AD(ref_rad(ihob-1:ihob+2),xi_AD_tl(ihob-1:ihob+2),&
         gpsptr%b_xj(j),&
         q_w(:,ihob),q_w_AD_tl(:,ihob),&
         q_w(:,ihob+1),q_w_AD_tl(:,ihob+1),&
         w4_AD_tl,dw4,dw4_AD_tl,4)
  end do ! grids dim
! END DO LOOP OVER OBS - each obs will have contributed to its profile

 ! Lagrange coefficients
  do k=nsig_up,1,-1
    call setq_AD(q_w_AD(:,k),ref_rad(k-1:k+1),xi_AD(k-1:k+1),3)
    call setq_AD(q_w_AD_tl(:,k),ref_rad(k-1:k+1),xi_AD_tl(k-1:k+1),3)
  enddo
  xi_AD(nsig_up-2)=xi_AD(nsig_up-2)+xi_AD(nsig_up+1)
  xi_AD(3)=xi_AD(3)+xi_AD(0)
  xi_AD_tl(nsig_up-2)=xi_AD_tl(nsig_up-2)+xi_AD_tl(nsig_up+1)
  xi_AD_tl(3)=xi_AD_tl(3)+xi_AD_tl(0)

! Extending atmosphere above nsig
  d_ref_rad_AD=zero
  d_ref_rad_AD_tl=zero
  do k=6,1,-1
    n_AD(nsig+k-1)=n_AD(nsig+k-1)+&
                   n_AD(nsig+k)*two*gpsptr%b_n(nsig+k-1)/gpsptr%b_n(nsig+k-2)
    n_AD(nsig+k-2)=n_AD(nsig+k-2)-&
                   (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_AD(nsig+k)
    xi_AD(nsig)=xi_AD(nsig)+xi_AD(nsig+k)
    d_ref_rad_AD=d_ref_rad_AD+k*xi_AD(nsig+k)
    n_AD_tl(nsig+k-1)=n_AD_tl(nsig+k-1)+&
                   n_AD_tl(nsig+k)*two*gpsptr%b_n(nsig+k-1)/gpsptr%b_n(nsig+k-2)
    n_AD_tl(nsig+k-2)=n_AD_tl(nsig+k-2)-&
                   (gpsptr%b_n(nsig+k-1)**2/gpsptr%b_n(nsig+k-2)**2)*n_AD_tl(nsig+k)
    xi_AD_tl(nsig)=xi_AD_tl(nsig)+xi_AD_tl(nsig+k)
    d_ref_rad_AD_tl=d_ref_rad_AD_tl+k*xi_AD_tl(nsig+k)
  end do
  xi_AD(nsig)=xi_AD(nsig)+d_ref_rad_AD
  xi_AD(nsig-1)=xi_AD(nsig-1)-d_ref_rad_AD
  xi_AD_tl(nsig)=xi_AD_tl(nsig)+d_ref_rad_AD_tl
  xi_AD_tl(nsig-1)=xi_AD_tl(nsig-1)-d_ref_rad_AD_tl

! Increment of refractivity and index of refractivity - radius product
  do k=1,nsig
    n_AD(k)=n_AD(k)+r1em6*gpsptr%b_rges(k)*xi_AD(k)
    h_AD(k)=h_AD(k)+gpsptr%b_gp2gm(k)*irefges(k)*xi_AD(k)
    t_AD(k)=t_AD(k)+gpsptr%b_tin(k)*n_AD(k)
    q_AD(k)=q_AD(k)+gpsptr%b_qin(k)*n_AD(k)
    p_AD=p_AD+gpsptr%b_pin(k)*n_AD(k)
    n_AD_tl(k)=n_AD_tl(k)+r1em6*gpsptr%b_rges(k)*xi_AD_tl(k)
    h_AD_tl(k)=h_AD_tl(k)+gpsptr%b_gp2gm(k)*irefges(k)*xi_AD_tl(k)
    t_AD_tl(k)=t_AD_tl(k)+gpsptr%b_tin(k)*n_AD_tl(k)
    q_AD_tl(k)=q_AD_tl(k)+gpsptr%b_qin(k)*n_AD_tl(k)
    p_AD_tl=p_AD_tl+gpsptr%b_pin(k)*n_AD_tl(k)
  end do

! geopotential heights
  height_AD=zero;dz_AD=zero;hk_AD=zero
  height_AD_tl=zero;dz_AD_tl=zero;hk_AD_tl=zero
  do k=1,nsig
     height_AD(k)=height_AD(k)+h_AD(k)
     height_AD_tl(k)=height_AD_tl(k)+h_AD_tl(k)
  end do
! rest of levels
  do k=nsig,2,-1
    height_AD(k-1)=height_AD(k-1)+height_AD(k)
    dz_AD(k)=dz_AD(k)+height_AD(k)
    hk_AD(k)=hk_AD(k)+dz_AD(k)*(gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
    t_AD(k-1) = t_AD(k-1)+rdog*half*hk_AD(k)
    t_AD(k)   = t_AD(k)+rdog*half*hk_AD(k)
    height_AD_tl(k-1)=height_AD_tl(k-1)+height_AD_tl(k)
    dz_AD_tl(k)=dz_AD_tl(k)+height_AD_tl(k)
    hk_AD_tl(k)=hk_AD_tl(k)+dz_AD_tl(k)*(gpsptr%b_pkges(k-1)-gpsptr%b_pkges(k))
    t_AD_tl(k-1) = t_AD_tl(k-1)+rdog*half*hk_AD_tl(k)
    t_AD_tl(k)   = t_AD_tl(k)+rdog*half*hk_AD_tl(k)
  end do
  dz_AD(1)=dz_AD(1)+height_AD(1)
  hk_AD(1)=hk_AD(1)+dz_AD(1)*(gpsptr%b_psges-gpsptr%b_pkges(1))
  t_AD(1)=t_AD(1)+ hk_AD(1)*rdog
  dz_AD_tl(1)=dz_AD_tl(1)+height_AD_tl(1)
  hk_AD_tl(1)=hk_AD_tl(1)+dz_AD_tl(1)*(gpsptr%b_psges-gpsptr%b_pkges(1))
  t_AD_tl(1)=t_AD_tl(1)+ hk_AD_tl(1)*rdog


! Interpolation

  do j=1,nsig
  rt(i1(j))=rt(i1(j))+w1_gps*t_AD(j)
  rt(i2(j))=rt(i2(j))+w2_gps*t_AD(j)
  rt(i3(j))=rt(i3(j))+w3_gps*t_AD(j)
  rt(i4(j))=rt(i4(j))+w4_gps*t_AD(j)

  rq(i1(j))=rq(i1(j))+w1_gps*q_AD(j)
  rq(i2(j))=rq(i2(j))+w2_gps*q_AD(j)
  rq(i3(j))=rq(i3(j))+w3_gps*q_AD(j)
  rq(i4(j))=rq(i4(j))+w4_gps*q_AD(j)

  rt_tl(i1(j))=rt_tl(i1(j))+w1_gps*t_AD_tl(j)
  rt_tl(i2(j))=rt_tl(i2(j))+w2_gps*t_AD_tl(j)
  rt_tl(i3(j))=rt_tl(i3(j))+w3_gps*t_AD_tl(j)
  rt_tl(i4(j))=rt_tl(i4(j))+w4_gps*t_AD_tl(j)

  rq_tl(i1(j))=rq_tl(i1(j))+w1_gps*q_AD_tl(j)
  rq_tl(i2(j))=rq_tl(i2(j))+w2_gps*q_AD_tl(j)
  rq_tl(i3(j))=rq_tl(i3(j))+w3_gps*q_AD_tl(j)
  rq_tl(i4(j))=rq_tl(i4(j))+w4_gps*q_AD_tl(j)
  enddo

  rp(i1(1))=rp(i1(1))+w1_gps*p_AD
  rp(i2(1))=rp(i2(1))+w2_gps*p_AD
  rp(i3(1))=rp(i3(1))+w3_gps*p_AD
  rp(i4(1))=rp(i4(1))+w4_gps*p_AD

  rp_tl(i1(1))=rp_tl(i1(1))+w1_gps*p_AD_tl
  rp_tl(i2(1))=rp_tl(i2(1))+w2_gps*p_AD_tl
  rp_tl(i3(1))=rp_tl(i3(1))+w3_gps*p_AD_tl
  rp_tl(i4(1))=rp_tl(i4(1))+w4_gps*p_AD_tl

  gpsptr => gpsptr%llpoint

  end do

  return
end subroutine intbend_tl

end module intbendmod