module berror 18,1
!$$$   module documentation block
!                .      .    .                                       .
! module:    berror    contains information pertaining to the background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: contains information pertaining to the background error
!
! program history log:
!   2004-01-01  kleist
!   2004-11-03  treadon - add horizontal scale weighting factors
!   2004-11-16  treadon - add longitude dimension to variance (dssv) array
!   2004-11-22  derber  - modify horizontal table definition
!   2005-01-22  parrish - clean up code by using module balmod
!   2005-02-23  wu      - add subroutine set_nrh_var
!   2005-05-24  pondeca - accommodate 2dvar only surface analysis option
!                         in set_predictors_var and create_berror_vars_reg
!   2005-06-06  wu - initialize logical fstat
!   2005-10-06  wu - set ozmz values in regional mode
!   2005-11-16  wgu - set nmix=nr+1+(ny-nlat)/2 to make sure
!               nmix+nrmxb=nr in routine smoothrf no matter what
!               number nlat is
!   2005-11-16  wgu - set ny to be odd number if nlat is odd number
!               to support GMAO grid 
!   2005-11-29  derber -  remove set_ozone_var (included in prewgt_reg and prewgt)
!   2006-01-09  derber - remove set_nrh_var and move capability to compute_derived
!   2006-04-21  kleist - add capability to perturb background error parameters 
!
! subroutines included:
!   sub init_berror         - initialize background error related variables
!   sub create_berror_vars  - allocate global background error related variables
!   sub destroy_berror_vars - deallocate global background error 
!                                    related variables
!   sub set_predictor_var   - set background variances for bias correction coefs
!   sub init_rftable        - load global/global pointers and tables for 
!                                    recursive filters
!   sub initable            - initialize tables/pointers for recursive filters
!   sub create_berror_vars_reg - allocate regional background error 
!                                    related variables
!   sub destroy_berror_vars_reg - deallocate regional background error 
!                                    related variables
!
! Variable Definitions:
!   def norh      - order of interpolations in smoother
!   def ndeg      - degree of smoothing
!   def nta       - first dimension of table (granularity of smoothing coef)
!   def nx        - number longitudes for rf patches
!   def ny        - number latitudes for rf patches
!   def mr        - subdomain dimension for patches
!   def nr        - subdomain dimension for patches
!   def nf        - subdomain dimension for patches
!   def nlath     - half the number of latitudes
!   def ii        - array that point to the x location in table for smoothing
!   def jj        - array that point to the y location in table for smoothing
!   def ii1       - array that point to the x location in table for smoothing
!                 - for northern pole patch
!   def jj1       - array that point to the y location in table for smoothing
!                 - for northern pole patch
!   def ii2       - array that point to the x location in table for smoothing
!                 - for southern pole patch
!   def jj2       - array that point to the y location in table for smoothing
!                 - for southern pole patch
!   def aw        - array that point to the x location in table for smoothing
!   def bw        - factor in background error calculation
!   def as        - normalized scale factor for background error (see namelist setup)
!   def vs        - scale factor for background error vertical scales
!   def be        - smoother coefficients
!   def bl        - blending coefficients for lat/lon boundaries
!   def bl2       - blending coefficients lat/lon boundaries
!   def varprd    - variance for predictors
!   def wmask     - not used, function of land-sea mask
!   def table     - table of coeffients for smoothing
!   def slw       - horizontal scale info for 1st patch
!   def slw1      - horizontal scale info for 2nd patch
!   def slw2      - horizontal scale info for 3rd patch
!   def wtaxs     - weights for polar-cascade interpolation
!   def wtxrs     - weights for the step, hybrid to polar grid
!   def inaxs     - index for polar-cascade interpolation
!   def inxrs     - index for polar-cascade interpolation
!   def dssv      - vertical smoother coefficients including variances
!   def dssvl     - variances for single level variables
!   def dssv2     - variances (lat,lon) for sea surface temperature
!   def alv       - vertical smoother coefficients
!   def hzscl     - scale factor for background error horizontal scales
!   def hswgt     - empirical weights to apply to each horizontal scale
!   def pert_berr - logical for turning on background error parameter perturbations
!   def pert_berr_fct - scaling factor for randum numbers for berror perturbations 
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$ end documentation block

  use kinds, only: r_kind,i_kind
  implicit none

  integer(i_kind) norh,ndeg,nta,nlath
  integer(i_kind) nx,ny,mr,nr,nf
  integer(i_kind),allocatable,dimension(:,:):: inaxs,inxrs
  integer(i_kind),allocatable,dimension(:,:,:,:):: ii,jj,ii1,jj1,ii2,jj2

  real(r_kind) bw,vs
  real(r_kind),dimension(10):: as
  real(r_kind),dimension(3):: hzscl,hswgt

  real(r_kind),allocatable,dimension(:):: be,bl,bl2,varprd
  real(r_kind),allocatable,dimension(:,:):: table,&
       slw,slw1,slw2
  real(r_kind),allocatable,dimension(:,:):: dssvl,dssv2
  real(r_kind),allocatable,dimension(:,:,:):: wtaxs,wtxrs
  real(r_kind),allocatable,dimension(:,:,:,:):: alv,dssv

  logical pert_berr
  real(r_kind) pert_berr_fct


contains

  subroutine init_berror 1,3
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    init_berror    initializes constants for the background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: intializes constants for the background error
!
! program history log:
!   2004-01-01  kleist
!   2004-11-03  treadon - add default definition for horizontal scale weighting factors
!   2005-06-06  wu - add logical fstat
!
!   input argument list:
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    use kinds, only: i_kind
    use constants, only:  zero,one,three
    use balmod, only: fstat
    implicit none
    integer(i_kind) i

    fstat = .false.
    pert_berr = .false.
    pert_berr_fct = zero
    norh=2
    ndeg=4
    nta=50000
    nlath=48

    bw=zero

    do i=1,10
       as(i)=0.60_r_kind
    end do

    do i=1,3
      hzscl(i)=one
      hswgt(i)=one/three
    end do
    vs=one/1.5_r_kind

  return
  end subroutine init_berror


  subroutine create_berror_vars 1,4
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    create_berror_vars    create arrays for global background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: creates arrays for global background error
!
! program history log:
!   2004-01-01  kleist
!   2004-07-28  treadon - remove subroutine argument list to --> use modules
!   2004-11-16  treadon - add longitude dimension to array dssv
!
!   input argument list:
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
  use balmod, only: llmin,llmax
  use gridmod, only: nlat,nlon,lat2,lon2,nsig,nsig1o
  use radinfo, only: jpch,npred
  use pcpinfo, only: jtype,npredp
  implicit none
  
  llmin=1
  llmax=nlat

! Grid constant to transform to 3 pieces

  nx=nlon*3/2  
  nx=nx/2*2
  ny=nlat*8/9
  ny=ny/2*2
  if(mod(nlat,2)/=0)ny=ny+1
  mr=0
  nr=nlat/4
  nf=nr
  nlath=nlat/2
  if(mod(nlat,2)/=0) nlath=nlath+1

  allocate(wtaxs(0:norh*2-1,nf,0:(nlon/8)-1), &
           wtxrs(0:norh*2-1,0:(nlon/8)-1,mr:nr), &
           be(ndeg), &
           bl(nx-nlon), &
           bl2(nr+1+(ny-nlat)/2), &
           alv(lat2,ndeg,nsig,6), &
           dssv(6,lat2,lon2,nsig),&
           dssvl(lat2,3),&
           dssv2(lat2,lon2))
  allocate(varprd(jpch*npred+jtype*npredp))
  allocate(inaxs(nf,nlon/8), &
           inxrs(nlon/8,mr:nr) )

  allocate(slw(ny*nx,nsig1o),&
           slw1((2*nf+1)*(2*nf+1),nsig1o),&
           slw2((2*nf+1)*(2*nf+1),nsig1o))
  allocate(ii(ny,nx,3,nsig1o),jj(ny,nx,3,nsig1o),&
           ii1(2*nf+1,2*nf+1,3,nsig1o),jj1(2*nf+1,2*nf+1,3,nsig1o),&
           ii2(2*nf+1,2*nf+1,3,nsig1o),jj2(2*nf+1,2*nf+1,3,nsig1o))

  return
 end subroutine create_berror_vars


  subroutine destroy_berror_vars 1
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    destroy_berror_vars  deallocates global background error arrays
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: deallocates global background error arrays
!
! program history log:
!   2004-01-01  kleist
!   2005-03-03  treadon - add implicit none
!
!   input argument list:
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    implicit none
    deallocate(wtaxs,wtxrs,be,table,bl,bl2,alv,&
               dssv,dssvl,dssv2,inaxs,inxrs,&
               varprd)
    deallocate(slw,slw1,slw2)
    deallocate(ii,jj,ii1,jj1,ii2,jj2)
    return
  end subroutine destroy_berror_vars


  subroutine set_predictors_var 1,5
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    set_predictors_var sets variances for bias correction predictors
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: sets variances for bias correction predictors
!
! program history log:
!   2004-01-01  kleist
!   2004-07-28  treadon - remove subroutine calling list, pass through module
!   2005-05-24  pondeca - take into consideration that nrclen=0 for 2dvar only
!                         surface analysis option
!
!   input argument list:
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    use kinds, only: i_kind,r_kind
    use constants, only:  one,one_tenth
    use radinfo, only: npred,jpch
    use pcpinfo, only: npredp,jtype
    use jfunc, only: nrclen
    implicit none

    integer(i_kind) i
    real(r_kind) stndev
    
    stndev = one/one_tenth       ! 0.316 K background error
    do i=1,max(1,nrclen)
       varprd(i)=stndev
    end do
    return
  end subroutine set_predictors_var


  subroutine init_rftable(mype,rate,sli,sli1,sli2) 2,10
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    init_rftable    initializes constants for the background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: intializes constants for the global background error
!
! program history log:
!   2004-01-01  kleist
!   2004-11-22  derber - modify to do both global and regional, make table
!                        reproducible with different number of processors and
!                        save only those elements of table which are used
!   2005-06-10  devenyi/treadon - remove mype from call rfdparv
!
!   input argument list:
!     sli      - horizontal scale info for 1st patch
!     sli1     - horizontal scale info for 2nd patch (optional)
!     sli2     - horizontal scale info for 3rd patch (optional)
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    use kinds, only: i_kind,r_kind
    use gridmod, only:  nsig,nsig1o,regional
    use mpimod, only:  levs_id,npe
    use constants, only: zero,one,two,four
    implicit none

    real(r_kind),parameter:: tin = 0.2e-3_r_kind

    integer(i_kind) i,j,k,n,nynx,nfnf
    integer(i_kind) nnn,mype,ihwlb
    integer(i_kind) nfg,ntax,iloc
    
    real(r_kind),optional,dimension((2*nf+1)*(2*nf+1),3,nsig1o):: sli1,sli2
    real(r_kind),dimension(ny*nx,3,nsig1o):: sli
    real(r_kind),dimension(ndeg):: rate
    real(r_kind):: hwlmax,hwlmin,hwlb,hwle,wni2
    real(r_kind),parameter:: r999         = 999.0_r_kind
    real(r_kind),allocatable,dimension(:):: dsh
    logical,allocatable,dimension(:):: iuse
    integer(i_kind),allocatable,dimension(:):: ipoint


    nynx=ny*nx
    if(.not. regional)then
      if(.not. present(sli1) .or. .not. present(sli2))then
         write(6,*)'INIT_RFTABLE:  ***ERROR*** sli1 or sli2 not present'
         call stop2(34)
      end if
      nfg=nf*2+1
      nfnf=nfg*nfg
    end if

    nnn=0
    do k=1,nsig1o
      if (levs_id(k)/=0) nnn=nnn+1
    end do

! Determine lower/upper bounds on scales
    hwlmax=-r999
    hwlmin=r999
    do k=1,nnn

!       Load slw arrays
        do j=1,nynx
           slw(j,k)=sli(j,1,k)
        end do
        do j=1,nynx
           hwlmax=max(hwlmax,sli(j,2,k))
           hwlmin=min(hwlmin,sli(j,2,k))
        end do
        do j=1,nynx
           hwlmax=max(hwlmax,sli(j,3,k))
           hwlmin=min(hwlmin,sli(j,3,k))
        end do
        if(.not. regional)then
          do j=1,nfnf
           slw1(j,k) = sli1(j,1,k)
           slw2(j,k) = sli2(j,1,k)
          end do
          do j=1,nfnf
           hwlmax=max(hwlmax,sli1(j,2,k))
           hwlmin=min(hwlmin,sli1(j,2,k))
           hwlmax=max(hwlmax,sli2(j,2,k))
           hwlmin=min(hwlmin,sli2(j,2,k))
          end do
          do j=1,nfnf
           hwlmax=max(hwlmax,sli1(j,3,k))
           hwlmin=min(hwlmin,sli1(j,3,k))
           hwlmax=max(hwlmax,sli2(j,3,k))
           hwlmin=min(hwlmin,sli2(j,3,k))
          end do
        end if
    enddo

! factor from multi-Gaussian RF
!   write(6,*)'INIT_RFTABLE:  hwlmax...=',hwlmax,hwlmin,&
!        hzscl(1),hzscl(2),hzscl(3),mype,nynx,nnn
    hwlmax=hwlmax*max(hzscl(1),hzscl(2),hzscl(3))
    hwlmin=hwlmin*min(hzscl(1),hzscl(2),hzscl(3))

! setup smoother coef and scale
    if (hwlmax==zero .or. hwlmin==zero) then
       write(6,*)'INIT_RFTABLE:  ***ERROR*** illegal value for min,max scale.',&
            '  hwlmin,hwlmax=',hwlmin,hwlmax,mype
       call stop2(41)
    endif
    hwlb=one/hwlmax
    hwle=one/hwlmin

    ihwlb=hwlb/tin
    hwlb=ihwlb*tin
!   tin=(hwle-hwlb)/float(nta-1)
    ntax=(hwle-hwlb)/tin+2
!   write(6,*)'INIT_RFTABLE:  tin ',ntax,ihwlb,tin,hwlb,hwle

    allocate(iuse(ntax))

    iuse=.false.
    wni2=one/tin
    do k=1,nnn
        do n=2,3
           do i=1,nynx
             do j=1,3
               iloc=min(ntax,nint(one+wni2*(one/(hzscl(j)*sli(i,n,k))-hwlb)))
               iuse(iloc)=.true.
             enddo
           enddo

           if(.not. regional)then
             do i=1,nfg*nfg
               do j=1,3
               iloc=min(ntax,nint(one+wni2*(one/(hzscl(j)*sli1(i,n,k))-hwlb)))
               iuse(iloc)=.true.
               iloc=min(ntax,nint(one+wni2*(one/(hzscl(j)*sli2(i,n,k))-hwlb)))
               iuse(iloc)=.true.
               enddo
             enddo
           end if

        enddo
    enddo
    nta=0
    allocate(dsh(ntax),ipoint(ntax))
    ipoint=0
    do i=1,ntax
      if(iuse(i))then
        nta=nta+1
        ipoint(i)=nta
        dsh(nta)=one/(float(i-1)*tin+hwlb)
      end if
    end do
!   write(6,*)'INIT_RFTABLE:  ntax,nta = ',ntax,nta

!   Loop over number of sigma levels per task    
    do k=1,nnn

!      Load pointers into table array
       do j=1,3

         call initable(ny,nx,sli(1,1,k),nta,ntax,hwlb,&
            ii(1,1,j,k),jj(1,1,j,k),hzscl(j),tin,ipoint)

         if(.not. regional)then
           call initable(nfg,nfg,sli1(1,1,k),nta,ntax,hwlb,&
            ii1(1,1,j,k),jj1(1,1,j,k),hzscl(j),tin,ipoint)

           call initable(nfg,nfg,sli2(1,1,k),nta,ntax,hwlb,&
            ii2(1,1,j,k),jj2(1,1,j,k),hzscl(j),tin,ipoint)
         end if

       end do

!   End of loop over number of sigma levels per mpi task       
    end do

    deallocate(iuse,ipoint)

    allocate(table(nta,ndeg)) 

    call rfdparv(dsh,rate,table,nta,ndeg)

    deallocate(dsh)

    return
  end subroutine init_rftable

  

  subroutine initable(nxdim,nydim,sli,nta,ntax,hwlb,iix,jjx,factor,tin,ipoint) 3,2
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    initable    initializes pointers to table for background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: initializes pointers to table for global and regional background error
!
! program history log:
!   2004-01-01  kleist
!   2004-11-22  derber  - modify to be consistent with init_rftable
!
!   input argument list:
!     nxdim    - 1st dimension of arrays
!     nydim    - 2nd dimension of arrays
!     sli      - horizontal scale info
!     nta      - number of entries in table array
!     ntax     - number of possible entries in table array
!     hwlb     - minimum of possible coefficient values
!     factor   - horizontal scale factor
!     tin      - table interval
!     ipoint   - pointer at table locations
!
!   output argument list:
!     iix      - first index pointer array to table
!     jjx      - second index pointer array to table
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    use kinds, only: r_kind,i_kind
    use constants, only: one
    implicit none

    integer(i_kind) iy,nydim,ix,nxdim,im,nta,iloc,ntax
    integer(i_kind),dimension(nxdim,nydim):: iix,jjx
    integer(i_kind),dimension(ntax):: ipoint

    real(r_kind) wni2,hwlb,factor,tin
    real(r_kind),dimension(nxdim,nydim,3):: sli

!   Load pointers for table array
    wni2=one/tin
    do iy=1,nydim
       do ix=1,nxdim
         iloc=min(ntax, max(1, nint(one+wni2*(one/(sli(ix,iy,2)*factor)-hwlb))))
         iix(ix,iy)=ipoint(iloc)
         iloc=min(ntax, max(1, nint(one+wni2*(one/(sli(ix,iy,3)*factor)-hwlb))))
         jjx(ix,iy)=ipoint(iloc)
       enddo
    enddo

    return
  end subroutine initable


  subroutine create_berror_vars_reg(mype) 1,5
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    create_berror_vars_reg  create arrays for reg background error
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: creates arrays for regional background error
!
! program history log:
!   2004-01-01  kleist
!   2004-07-28  treadon - simplify subroutine calling list
!   2004-11-16  treadon - add longitude dimension to array dssv
!   2005-05-24  pondeca - take into consideration that npred=npredp=0
!                         for 2dvar only surface analysis option
!   2005-06-23  middlecoff/treadon - iniitalize mr,nr,nf
!
!   input argument list:
!
!   output argument list:
!     mype     - mpi task id
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    use kinds, only: i_kind
    use balmod, only: llmin,llmax
    use gridmod, only: nlat,nlon,nsig,nsig1o,lat2,lon2
    use radinfo, only: jpch,npred
    use pcpinfo, only: jtype,npredp
    implicit none
    
    integer(i_kind),intent(in):: mype
    
    nx=nlon
    ny=nlat
    mr=1
    nr=1
    nf=nr
    
!   Grid constant for background error

    allocate(be(ndeg), &
         alv(llmin:llmax,ndeg,nsig,6), &
         dssv(6,llmin:llmax,lon2,nsig), &
         dssvl(llmin:llmax,3), &
         dssv2(lat2,lon2))
    
    allocate(varprd(max(1,jpch*npred+jtype*npredp) ) )     

    allocate(slw(ny*nx,nsig1o) )
    allocate(ii(ny,nx,3,nsig1o),jj(ny,nx,3,nsig1o) )
    
    
    return
  end subroutine create_berror_vars_reg


  subroutine destroy_berror_vars_reg 1
!$$$  subprogram documentation block
!                .      .    .                                       .
! subprogram:    destroy_berror_vars_reg  deallocate reg background error arrays
!   prgmmr: kleist           org: np20                date: 2004-01-01
!
! abstract: deallocates regional background error arrays
!
! program history log:
!   2004-01-01  kleist
!   2005-03-03  treadon - add implicit none
!
!   input argument list:
!
!   output argument list:
!
! attributes:
!   language: f90
!   machine:  ibm RS/6000 SP
!
!$$$
    implicit none
    deallocate(be,table,alv,&
               dssv,dssvl,dssv2,&
               varprd)
    deallocate(slw)
    deallocate(ii,jj)
    return
  end subroutine destroy_berror_vars_reg

end module berror