    module covar_setup
!  COVAR_SETUP - read the ensemble covariance inflation file and report
!  the nature of the covariance inflation that is to be applied to the
!  ensemble at each vertical level.
!  MODIFICATION HISTORY
!  07/11/05 - deleted sigma file name from vertical information file;
!             see read_vert_info_file.
!  06/23/05 - added support for enhanced inflation on selected variables.
!  06/21/05 - added support for enhanced variance inflation
!  01/27/05 - new version to add the Zhang, Snyder, and Sun correction to
!    the analysis ensemble.  The covariance data file is NOT COMPATIBLE
!    with that of previous versions of the code.
!
    use grid_types
    use assim_vars
    use io
    implicit none
!
!  Types of variance inflation that the program eventually can handle.
!  "Zhang" inflation is the linear combination (homotopy) of the background
!  ensemble differences and the analysis ensemble differences computed by
!  the EKTF.  If alpha=0.5, for example, we take the average of the two
!  for the final analysis.  The goal is to keep the ensemble from collapsing.
!  See Zhang, Snyder, and Sun, MWR 132 (May 2004), 1238-1253, Eq. (5).
!  By default, we don't apply the Zhang inflation (i.e., alpha=0).
!  Values of alpha < 1 mean to move the analysis ensemble closer to the
!  background.  We require 0 <= alpha < 1.
!
    type inflation_info
       sequence
       real(R)::covar=0.04_R  ! size of covariance inflation; 4% by default
       real(R)::enhanced=0.0  ! size of enhanced inflation; none by default
       real(R)::alpha=0.0  ! Snyder-Zhang inflation term
    end type inflation_info
!
!  Vertical radius and inflation info by level and latitude
!
    type(inflation_info),save,private::infl(LEVS,LATG)
!
    integer,save,private::enhanced_inflation_varlist(NAVARS)= &
       (/PRES_TYPE,TEMP_TYPE,UWIND_TYPE,VWIND_TYPE/)
    contains
!---------------------------------------------------------------------------
    pure subroutine inflation(loc,inflate,vars)
!  INFLATION - return the covariance inflation factor and method, and optionally
!  the list of variables for which enhanced inflation is to be attempted
!  for the patch centered at LOC.
!
    type(patch_index),intent(in)::loc
    type(inflation_info),intent(out)::inflate
    integer,intent(out),optional::vars(NAVARS)
!
    if(loc%z.lt.1.or.loc%z.gt.LEVS.or.loc%y.lt.1.or.loc%y.gt.LATG) then
       inflate=inflation_info(0.0,0.0,0.0)   ! out of bounds
    else
       inflate=infl(loc%z,loc%y)
    endif
    if(present(vars)) vars=enhanced_inflation_varlist
    return
    end subroutine inflation
!---------------------------------------------------------------------------
    subroutine read_vert_info_file(zfile,zradius)
!  READ_VERT_INFO_FILE - read the file containing information about the
!  vertical localization, and covariance inflation and method at each 
!  level.
!  Because it seems most convenient to have one file to specify vertical
!  localization and covariance data, this routine is placed in this module,
!  even though the vertical level thickness arguably belongs to the indexing
!  routines.
!  The format of the user-created input file is as follows:
!  Lines beginning with # are comments.
!  All subsequent non-comment lines have the form
!    startlat endlat
!    level  zradius  covariance method alpha.
!  The values for the indicated levels apply for all
!  latitudes in the range from STARTLAT to ENDLAT.
!  If no vertical localization is to be done, but we do want covariance
!  inflation, then set the Z radius to LEVS (28).
!
    implicit none
    character(*),intent(in)::zfile
    integer,intent(out)::zradius(LEVS,LATG)
!
!  Local variables
!
    integer::j,lowlat,highlat,prevhigh,lev,lineno,zwin
    real(R)::covar,alpha,enhanced
    character(80)::line
    logical::eof
!
    if(len_trim(zfile).eq.0) return
    if(verbosity().gt.VERB_SILENT) write(LOGFILE,100) trim(zfile)
100 format('vertical localization data file: ',a)
    open(unit=IN,file=zfile,status='old',iostat=j)
    if(j.ne.0) call fexit('read_vert_info_file: cannot open '//trim(zfile),2)
!
!  Subsequent lines:  look for
!   startlat endlat
!  followed by
!   lev zradius covariance alpha
!  and do basic sanity checks.
!
    lineno=0
    prevhigh=0
    do
       call skip_comments(line,lineno,eof)
       if(eof) exit
       read(line,*) lowlat,highlat
       if(lowlat.ne.prevhigh+1.or.highlat.lt.lowlat) then
          write(IERR,900) trim(zfile),lineno,'latitudes overlap'
900       format(a,': line ',i0,': ',a)
          write(IERR,901) lowlat,highlat,prevhigh
901       format('lowlat: ',i0,' highlat: ',i0,' prevhigh: ',i0)
          call fexit(trim(zfile)//': error in input',2)
       else if(highlat.lt.1.or.highlat.gt.LATG) then
          write(IERR,900) trim(zfile),lineno,'bad latitude value'
          call fexit(trim(zfile)//': error in input',2)
       endif
       prevhigh=highlat
       do j=1,LEVS
          call skip_comments(line,lineno,eof)
          if(eof) goto 10   ! quit
          read(line,*) lev,zwin,covar,alpha,enhanced
          if(min(covar,alpha,enhanced).lt.0.0.or.alpha.ge.1.0) then
             write(IERR,900) trim(zfile),lineno,'bad variance inflation value'
             call fexit(trim(zfile)//': error in input',2)
          endif
          if(lev.ne.j) then
             write(IERR,900) trim(zfile),lineno,'bad level index'
             call fexit(trim(zfile)//': error in input',2)
          else if(lev.eq.1.and.zwin.eq.LEVS) then   ! no vertical localization
             zradius(:,lowlat)=LEVS
             infl(:,lowlat)%covar=covar
             infl(:,lowlat)%alpha=alpha
             infl(:,lowlat)%enhanced=enhanced
             exit
          else if(lev+zwin.gt.LEVS.or.lev-zwin.lt.1) then
             write(IERR,900) trim(zfile),lineno,'z radius out of range'
             call fexit(trim(zfile)//': error in input',2)
          else
             zradius(j,lowlat)=zwin
             infl(j,lowlat)%covar=covar
             infl(j,lowlat)%alpha=alpha
             infl(j,lowlat)%enhanced=enhanced
          endif
       enddo
       !
       !  The thickness of the layers is independent of longitude for now
       !
       do j=lowlat+1,highlat
          infl(:,j)=infl(:,lowlat)
          zradius(:,j)=zradius(:,lowlat)
       enddo
    enddo
 10 continue
    close(IN)
    return
    contains
       ! -------------------
       subroutine skip_comments(ln,no,eof)
       !  SKIP_COMMENTS - skip blank and comment lines
       !
       character(*),intent(out)::ln
       integer,intent(inout)::no
       logical,intent(out)::eof
       !
       eof=.false.
       do
          no=no+1
          read(IN,'(a)',end=90) ln
          if(ln(1:1).ne.'#'.and.len_trim(ln).gt.0) exit
       enddo
       return
 90    eof=.true.
       return
       end subroutine skip_comments
       ! -------------------
    end subroutine read_vert_info_file
!---------------------------------------------------------------------------
    end module covar_setup
