PROGRAM arpsdas,315
!
!##################################################################
!##################################################################
!######                                                      ######
!######                   PROGRAM ARPSDAS                    ######
!######             ARPS Data Analysis System                ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!
!  PURPOSE:
!
!  This program does three-dimensional data analyses on
!  the ARPS grid.  It is loosely based on the rewritten
!  OLAPS surface analysis.
!
!  The driver establishes sizing of variables
!  and adjustable parameters.
!  It calls a routine to set up the grid, calls the data readers,
!  a routine to analyse the data and another to write it out.
!
!  AUTHOR:
!
!  Keith Brewster, CAPS, March, 1994
!  OLAPS sfc analysis Keith Brewster, CAPS, March, 1994
!
!  MODIFICATION HISTORY:
!  01/17/96  (KB) Named changed to ADAS, dimensions imported from
!            adas.dims and input variables from namelist
!            rather than parameter statements in this code.
!  11/27/96  (KB) Cleaned-up to remove unused arrays.
!  01/25/96  (KB) Added tem variables passed to anxiter to accomodate
!            new version of anxiter to speed-up execution.
!  06/15/97  (KB) Update for version 4.3.0, new arguments to call
!            to INITVAR.
!  07/16/97  (KB) Added nt to calling list of INITVAR and made nt
!            equal to one to save memory.
!  05/26/98  (KB) Modified logic in superadiabatic check. (kb)
!  08/31/98  (KB) Added code for nudging to official version (kb)
!  09/22/98  Jason Levit
!            Updated call in initgrdvar for arps4.4.0, including
!            change of dimension for qcumsrc.
!  12/07/98  Added background-based surface correlations to
!            account for cumulus-parameterization small-scale changes.
!  12/20/98  Changed moisture analysis variable to qv.
!            Error stats are still in RH, converted to qv based on
!            background value.
!  12/30/98  Added processing of qr from retrieval data.
!
!  2000/04/14 (Gene Bassett)
!            Merged the ADAS input file back into the ARPS input file.
!
!  2000/05/09 (Gene Bassett)
!            Converted to F90, creating allocation and adas main
!            subroutines.
!
!  2000/07/28 (Ming Xue)
!            Converted to F90 free format. Did away with adaasamin for 
!            better compilation efficiency. Use ALLOCATABLE instead of
!            POINTER allocation to avoid double memory usage.
!
!  07/23/2001 (K. Brewster)
!            Added dynamic array allocation for the IAU increment arrays.
!            Made corresponding changes to the increment handling 
!            routines to account for the array allocation.
!
!  08/07/2001 (K. Brewster)
!            Added a preliminary calculation of vertical velocity 
!            before the cloud analyis (before cmpclddrv call).
!
!  11/01/2001 (K. Brewster)
!            Renamed radar_ref_3d array to ref_mos_3d since its a mosaic.
!            Removed potentially very large 4-d temporary arrays for 
!            radar by reorganizing logic for radar mosaic creation.
!
!  04/10/2002 (K. Brewster)
!            Added code for soil surface temperature adjustment.
!            Includes allocation and deallocation of arrays temporarily
!            needed for radiation calculations.
!
!  05/16/2002 (K. Brewster)
!            Added BMJ arrays to initgrdvar call to conform with
!            latest updates to that subroutine.  Added deallocate after
!            the call to initgrdvar for some arrays not needed after
!            that call.
!
!  06/10/2002 (Eric Kemp)
!            Addition of new soil model variables.
!
!  04/09/2003 (K. Brewster)
!            Modified I/O of source errors to stop if I/O problem. 
!            Correction of problem in super-obbing.
!
!  03/01/2005 (S. Leyton and D. Weber)
!            Add MPI capabilities.
!
!  12/01/2005 (K. W. Thomas)
!            Update MPI capabilities.
!
!-----------------------------------------------------------------------
!
!  Variable Declarations:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE
!
  INCLUDE 'alloc.inc'

  INCLUDE 'adas.inc'
  INCLUDE 'nudging.inc'
  INCLUDE 'exbc.inc'
  INCLUDE 'radcst.inc'
  INCLUDE 'mp.inc'     ! Message passing parameters

  REAL :: exbcbuf( 1 ) ! EXBC buffer array (unused)
!
!-----------------------------------------------------------------------
!
!  Arrays defining model grid
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: x     (:)      ! The x-coord. of the physical and
                                      ! computational grid. Defined at u-point.
  REAL, ALLOCATABLE :: y     (:)      ! The y-coord. of the physical and
                                      ! computational grid. Defined at v-point.
  REAL, ALLOCATABLE :: z     (:)      ! The z-coord. of the computational grid.
                                      ! Defined at w-point on the staggered grid.
  REAL, ALLOCATABLE :: zp    (:,:,:)  ! The physical height coordinate defined at
                                      ! w-point of the staggered grid.
  REAL, ALLOCATABLE :: zpsoil(:,:,:)  ! Soil level depth.

  REAL, ALLOCATABLE :: hterain(:,:)   ! The height of the terrain.
  REAL, ALLOCATABLE :: mapfct(:,:,:)  ! Map factors at scalar, u and v points

  REAL, ALLOCATABLE :: j1    (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as - d( zp )/d( x ).
  REAL, ALLOCATABLE :: j2    (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as - d( zp )/d( y ).
  REAL, ALLOCATABLE :: j3    (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as d( zp )/d( z ).
  REAL, ALLOCATABLE :: j3soil(:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as d( zpsoil )/d( z ).
  REAL, ALLOCATABLE :: aj3x  (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as d( zp )/d( z ) AVERAGED IN THE X-DIR.
  REAL, ALLOCATABLE :: aj3y  (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as d( zp )/d( z ) AVERAGED IN THE Y-DIR.
  REAL, ALLOCATABLE :: aj3z  (:,:,:)  ! Coordinate transformation Jacobian defined
                                      ! as d( zp )/d( z ) AVERAGED IN THE Z-DIR.
  REAL, ALLOCATABLE :: j3inv (:,:,:)  ! Inverse of j3
  REAL, ALLOCATABLE :: j3soilinv (:,:,:)! Inverse of j3soil
!
!-----------------------------------------------------------------------
!
!  ARPS Time-dependent variables
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: u     (:,:,:)  ! Total u-velocity (m/s)
  REAL, ALLOCATABLE :: v     (:,:,:)  ! Total v-velocity (m/s)
  REAL, ALLOCATABLE :: w     (:,:,:)  ! Total w-velocity (m/s)
  REAL, ALLOCATABLE :: wcont (:,:,:)  ! Contravariant vertical velocity (m/s)
  REAL, ALLOCATABLE :: ptprt (:,:,:)  ! Perturbation potential temperature (K)
  REAL, ALLOCATABLE :: pprt  (:,:,:)  ! Perturbation pressure (Pascal)

  REAL, ALLOCATABLE :: qv    (:,:,:)  ! Water vapor specific humidity (kg/kg)
  REAL, ALLOCATABLE :: qc    (:,:,:)  ! Cloud water mixing ratio (kg/kg)
  REAL, ALLOCATABLE :: qr    (:,:,:)  ! Rain water mixing ratio (kg/kg)
  REAL, ALLOCATABLE :: qi    (:,:,:)  ! Cloud ice mixing ratio (kg/kg)
  REAL, ALLOCATABLE :: qs    (:,:,:)  ! Snow mixing ratio (kg/kg)
  REAL, ALLOCATABLE :: qh    (:,:,:)  ! Hail mixing ratio (kg/kg)
  REAL, ALLOCATABLE :: tke   (:,:,:)  ! Turbulent Kinetic Energy ((m/s)**2)

  REAL, ALLOCATABLE :: ubar  (:,:,:)  ! Base state u-velocity (m/s)
  REAL, ALLOCATABLE :: vbar  (:,:,:)  ! Base state v-velocity (m/s)
  REAL, ALLOCATABLE :: ptbar (:,:,:)  ! Base state potential temperature (K)
  REAL, ALLOCATABLE :: pbar  (:,:,:)  ! Base state pressure (Pascal).
  REAL, ALLOCATABLE :: rhostr(:,:,:)  ! Base state density rhobar times j3.
  REAL, ALLOCATABLE :: qvbar (:,:,:)  ! Base state water vapor specific
                                      ! humidity(kg/kg)

  REAL, ALLOCATABLE :: udteb (:,:)    ! T-tendency of u at e-boundary (m/s**2)
  REAL, ALLOCATABLE :: udtwb (:,:)    ! T-tendency of u at w-boundary (m/s**2)
  REAL, ALLOCATABLE :: vdtnb (:,:)    ! T-tendency of v at n-boundary (m/s**2)
  REAL, ALLOCATABLE :: vdtsb (:,:)    ! T-tendency of v at s-boundary (m/s**2)

  REAL, ALLOCATABLE :: pdteb (:,:)    ! T-tendency of pprt at e-boundary (PASCAL/s)
  REAL, ALLOCATABLE :: pdtwb (:,:)    ! T-tendency of pprt at w-boundary (PASCAL/s)
  REAL, ALLOCATABLE :: pdtnb (:,:)    ! T-tendency of pprt at n-boundary (PASCAL/s)
  REAL, ALLOCATABLE :: pdtsb (:,:)    ! T-tendency of pprt at s-boundary (PASCAL/s)
  REAL, ALLOCATABLE :: trigs1(:)      ! Array containing pre-computed trig
                                      ! function for use in fft.
  REAL, ALLOCATABLE :: trigs2(:)      ! Array containing pre-computed trig
                                      ! function for use in fft.
  INTEGER, ALLOCATABLE :: ifax1(:)    ! Array containing the factors of nx.
  INTEGER, ALLOCATABLE :: ifax2(:)    ! Array containing the factors of ny.
  REAL, ALLOCATABLE :: vwork1 (:,:)   ! 2-D work array for fftopt=2.
  REAL, ALLOCATABLE :: vwork2 (:,:)   ! 2-D work array for fftopt=2.
  REAL, ALLOCATABLE :: wsave1 (:)     ! Work array for fftopt=2.
  REAL, ALLOCATABLE :: wsave2 (:)     ! Work array for fftopt=2.

  REAL, ALLOCATABLE :: ppi(:,:,:)     ! Exner function.
  REAL, ALLOCATABLE :: csndsq(:,:,:)  ! Speed of sound squared
 
  REAL, ALLOCATABLE :: radfrc(:,:,:)  ! Radiation forcing (K/s)
  REAL, ALLOCATABLE :: radsw(:,:)     ! Solar radiation reaching the surface
  REAL, ALLOCATABLE :: rnflx(:,:)     ! Net absorbed radiation by the surface
  REAL, ALLOCATABLE :: radswnet(:,:)  ! Net shortwave radiation
  REAL, ALLOCATABLE :: radlwin(:,:)   ! Incominging longwave radiation

!
!-----------------------------------------------------------------------
!
!  ARPS Surface variables:
!
!-----------------------------------------------------------------------
!
  INTEGER, ALLOCATABLE :: soiltyp (:,:,:) ! Soil type
  REAL, ALLOCATABLE ::    stypfrct(:,:,:) ! Soil type fraction
  INTEGER, ALLOCATABLE :: vegtyp (:,:)    ! Vegetation type
  REAL, ALLOCATABLE ::    lai    (:,:)    ! Leaf Area Index
  REAL, ALLOCATABLE ::    roufns (:,:)    ! Surface roughness
  REAL, ALLOCATABLE ::    veg    (:,:)    ! Vegetation fraction

  REAL, ALLOCATABLE :: tsoil(:,:,:,:) ! Soil temperature (K)
  REAL, ALLOCATABLE :: qsoil(:,:,:,:) ! Soil moisture
  REAL, ALLOCATABLE :: qvsfc(:,:,:)   ! Effective qv at sfc.

  REAL, ALLOCATABLE :: wetcanp(:,:,:) ! Canopy water amount
  REAL, ALLOCATABLE :: snowdpth(:,:)  ! Snow depth (:)

  REAL, ALLOCATABLE :: ptcumsrc(:,:,:)! Source term in pt-equation due
                                      ! to cumulus parameterization
  REAL, ALLOCATABLE :: qcumsrc(:,:,:,:) ! Source term in Qv equation due
                                      ! to cumulus parameterization

  REAL, ALLOCATABLE :: w0avg(:,:,:)   ! a closing running average vertical
                                      ! velocity in 10min for K-F scheme
  REAL, ALLOCATABLE :: kfraincv(:,:)  ! K-F convective rainfall (:)
  INTEGER, ALLOCATABLE :: nca(:,:)    ! K-F counter for CAPE release
  REAL, ALLOCATABLE :: cldefi(:,:)    ! BMJ cloud efficiency
  REAL, ALLOCATABLE :: xland(:,:)     ! BMJ land mask
                                      !   (1.0 = land, 2.0 = sea)
  REAL, ALLOCATABLE :: bmjraincv(:,:) ! BMJ convective rainfall (cm)


  REAL, ALLOCATABLE :: raing(:,:)     ! Grid supersaturation rain
  REAL, ALLOCATABLE :: rainc(:,:)     ! Cumulus convective rain
  REAL, ALLOCATABLE :: prcrate(:,:,:) ! precipitation rate (kg/(m**2*s))
                                      ! prcrate(:,:,:) = total precipitation rate
                                      ! prcrate(:,:,:) = grid scale precip. rate
                                      ! prcrate(:,:,:) = cumulus precip. rate
                                      ! prcrate(:,:,:) = microphysics precip. rate

  REAL, ALLOCATABLE :: usflx (:,:)    ! Surface flux of u-momentum (kg/(m*s**2))
  REAL, ALLOCATABLE :: vsflx (:,:)    ! Surface flux of v-momentum (kg/(m*s**2))
  REAL, ALLOCATABLE :: ptsflx(:,:)    ! Surface heat flux (K*kg/(m*s**2))
  REAL, ALLOCATABLE :: qvsflx(:,:)    ! Surface moisture flux (kg/(m**2*s))
!
!-----------------------------------------------------------------------
!
!  Arrays for analysis increment updating (a type of nudging) output
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: uincr(:,:,:)
  REAL, ALLOCATABLE :: vincr(:,:,:)
  REAL, ALLOCATABLE :: wincr(:,:,:)
  REAL, ALLOCATABLE :: pincr(:,:,:)
  REAL, ALLOCATABLE :: ptincr(:,:,:)
  REAL, ALLOCATABLE :: qvincr(:,:,:)
  REAL, ALLOCATABLE :: qcincr(:,:,:)
  REAL, ALLOCATABLE :: qrincr(:,:,:)
  REAL, ALLOCATABLE :: qiincr(:,:,:)
  REAL, ALLOCATABLE :: qsincr(:,:,:)
  REAL, ALLOCATABLE :: qhincr(:,:,:)
!
!-----------------------------------------------------------------------
!
!  Analysis scratch space
!
!-----------------------------------------------------------------------
!
  INTEGER, ALLOCATABLE :: knt(:,:)
  REAL, ALLOCATABLE :: rngsqi(:)
  REAL, ALLOCATABLE :: wgtsum(:,:)
  REAL, ALLOCATABLE :: zsum(:,:)
  REAL, ALLOCATABLE :: sqsum(:,:)
!
!-----------------------------------------------------------------------
!
!  Additional grid variables
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: xs(:), xslg(:)
  REAL, ALLOCATABLE :: ys(:), yslg(:)
  REAL, ALLOCATABLE :: zs(:,:,:)
  REAL, ALLOCATABLE :: latgr(:,:)
  REAL, ALLOCATABLE :: longr(:,:)
!
!-----------------------------------------------------------------------
!
!  Temporary arrays.  Some are only used for MPI
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: tem1  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem2  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem3  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem4  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem5  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem6  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem7  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem8  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem9  (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem10 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem11 (:,:,:)     ! Temporary work array.
  INTEGER, ALLOCATABLE :: item1(:)       ! Temporary work array.
  INTEGER, ALLOCATABLE :: ibegin(:)
  INTEGER, ALLOCATABLE :: iend(:)

  INTEGER, ALLOCATABLE :: tems1di(:)
  INTEGER, ALLOCATABLE :: temr1di(:)
  REAL, ALLOCATABLE :: tems1dr(:)
  REAL, ALLOCATABLE :: temr1dr(:)

  REAL, ALLOCATABLE :: tems2dr(:,:)
  REAL, ALLOCATABLE :: temr2dr(:,:)

!
! Multi-level needs to handle "trnua", which is 2D.  The above two temporary
! arrays need to be preserved for "anxiter".
!

  REAL, ALLOCATABLE :: tems2drua(:,:)
  REAL, ALLOCATABLE :: temr2drua(:,:)

  REAL, ALLOCATABLE :: tems3dr(:,:,:)
  REAL, ALLOCATABLE :: temr3dr(:,:,:)
!
!-----------------------------------------------------------------------
!
!  Radiation variables only needed for adjtsfc
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: rsirbm(:,:)
  REAL, ALLOCATABLE :: rsirdf(:,:)
  REAL, ALLOCATABLE :: rsuvbm(:,:)
  REAL, ALLOCATABLE :: rsuvdf(:,:)
  REAL, ALLOCATABLE :: cosz(:,:)
  REAL, ALLOCATABLE :: cosss(:,:)
  REAL, ALLOCATABLE :: fdirir(:,:)
  REAL, ALLOCATABLE :: fdifir(:,:)
  REAL, ALLOCATABLE :: fdirpar(:,:)
  REAL, ALLOCATABLE :: fdifpar(:,:)
  REAL, ALLOCATABLE :: radbuf(:)
  REAL, ALLOCATABLE :: sh(:,:)           !added by DTD

  REAL, ALLOCATABLE :: temrad1 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem12 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem13 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem14 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem15 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem16 (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem17 (:,:,:)     ! Temporary work array. added by DTD

  REAL, ALLOCATABLE :: tem1soil (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem2soil (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem3soil (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem4soil (:,:,:)     ! Temporary work array.
  REAL, ALLOCATABLE :: tem5soil (:,:,:)     ! Temporary work array.
!
!-----------------------------------------------------------------------
!
!  Cloud analysis variables other than model's ones:
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: ref_mos_3d (:,:,:)
                     ! 3D remapped radar reflectivity field as input
                     ! may be modified by sate. VIS as output
  REAL, ALLOCATABLE :: w_cld (:,:,:)      ! vertical velocity (m/s) in clouds
  INTEGER, ALLOCATABLE :: cldpcp_type_3d(:,:,:)
                                       ! cloud/precip type field

  INTEGER, ALLOCATABLE :: icing_index_3d(:,:,:) ! icing severity index
  LOGICAL, ALLOCATABLE :: l_mask_pcptype(:,:) ! analyze precip type 
!
!-----------------------------------------------------------------------
!
!  Analysis variables
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: anx(:,:,:,:)
!
!-----------------------------------------------------------------------
!
!  Cross-category correlations
!
!-----------------------------------------------------------------------
!
  REAL,    ALLOCATABLE :: xcor(:,:)
  INTEGER, ALLOCATABLE :: icatg(:,:)
!
!-----------------------------------------------------------------------
!
!  ARPS dimensions:
!
!  nx, ny, nz: Dimensions of analysis grid.
!
!-----------------------------------------------------------------------
!
  INTEGER :: nx       ! Number of grid points in the x-direction
  INTEGER :: ny       ! Number of grid points in the y-direction
  INTEGER :: nz       ! Number of grid points in the z-direction
  INTEGER :: nzsoil   ! Number of soil levels

  INTEGER :: nxlg     ! Number of grid points in the x-direction large grid
  INTEGER :: nylg     ! Number of grid points in the y-direction large grid

  INTEGER :: nxndg    ! Number of x grid points for IAU
  INTEGER :: nyndg    ! Number of y grid points for IAU
  INTEGER :: nzndg    ! Number of z grid points for IAU
!
!-----------------------------------------------------------------------
!
!  Soil types.
!
!-----------------------------------------------------------------------
!
  INTEGER :: nstyps            ! Number of soil types
!
!-----------------------------------------------------------------------
!
!  Misc
!
!-----------------------------------------------------------------------
!
  INTEGER :: nt                ! Number of time levels of data
  INTEGER :: ncat              ! Number of correlation categories
  REAL :: rlim                 ! Largest possible radius of influence

!-----------------------------------------------------------------------
!
!  Analysis parameters
!
!-----------------------------------------------------------------------
!
  REAL,    PARAMETER :: rhmin=0.05  ! rh safety net value to prevent neg qv
  INTEGER, PARAMETER :: iqspr=3     ! Use qobs of pstn to combine x,y,elev
  INTEGER, PARAMETER :: klim= 1     ! Min of one other sfc station for QC
!
!-----------------------------------------------------------------------
!
!  Indices of specific observation variables
!
!-----------------------------------------------------------------------
!
  INTEGER, PARAMETER :: ipres=3   ! Pressure
  INTEGER, PARAMETER :: iptmp=4   ! Potential Temperature
  INTEGER, PARAMETER :: iqv=5     ! Specific Humidity
!
!-----------------------------------------------------------------------
!
!  ARPS cloud cover analysis variables:
!
!-----------------------------------------------------------------------
!
! Remapping parameters of the remapped radar data grid
!
  INTEGER :: strhopt_rad                  ! streching option
  INTEGER :: mapproj_rad                  ! map projection indicator
  REAL :: dx_rad,dy_rad,dz_rad,dzmin_rad  ! grid spcngs
  REAL :: ctrlat_rad,ctrlon_rad           ! central lat and lon
  REAL :: tlat1_rad,tlat2_rad,tlon_rad    ! true lat and lon
  REAL :: scale_rad                       ! map scale factor
!
!-----------------------------------------------------------------------
!
!  Common block that stores remapping parameters for the radar
!  data file.
!
!-----------------------------------------------------------------------
!
  COMMON /remapfactrs_rad/ strhopt_rad,mapproj_rad
  COMMON /remapfactrs_rad2/ dx_rad,dy_rad,dz_rad,dzmin_rad,             &
           ctrlat_rad,ctrlon_rad,                                       &
           tlat1_rad,tlat2_rad,tlon_rad,scale_rad
!
!-----------------------------------------------------------------------
!
!  ARPS include files
!
!-----------------------------------------------------------------------
!
  INCLUDE 'globcst.inc'
  INCLUDE 'phycst.inc'
  INCLUDE 'bndry.inc'
  INCLUDE 'grid.inc'        ! Grid parameters
  INCLUDE 'adjust.inc'
!
!-----------------------------------------------------------------------
!
!  Surface Station variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: isrcsng(mx_sng)
  INTEGER :: icatsng(mx_sng)
  REAL :: latsng(mx_sng,ntime)
  REAL :: lonsng(mx_sng,ntime)
  REAL :: hgtsng(mx_sng,ntime)
  REAL :: xsng(mx_sng)
  REAL :: ysng(mx_sng)
  REAL :: trnsng(mx_sng)
  INTEGER :: timesng(mx_sng,ntime)
  CHARACTER (LEN=5) :: stnsng(mx_sng,ntime)
!
!-----------------------------------------------------------------------
!
!  Surface (single-level) read-in observation variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=8) :: wx(mx_sng,ntime)
  CHARACTER (LEN=8) :: csrcsng(mx_sng,ntime)
  CHARACTER (LEN=1) :: store_emv(mx_sng,5,ntime)
  CHARACTER (LEN=4) :: store_amt(mx_sng,5,ntime)
  INTEGER :: kloud(mx_sng,ntime),idp3(mx_sng,ntime)
  REAL :: store_hgt(mx_sng,5,ntime)
  REAL :: obrdsng(mx_sng,nvar_sng,ntime)
  REAL :: obsng(nvar_anx,mx_sng)
  REAL :: odifsng(nvar_anx,mx_sng)
  REAL :: corsng(nvar_anx,mx_sng)
  REAL :: oanxsng(nvar_anx,mx_sng)
  REAL :: thesng(mx_sng)
  INTEGER :: ival(mx_sng)
!
!-----------------------------------------------------------------------
!
!  Upper Air Station variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: isrcua(mx_ua)
  REAL :: xua(mx_ua)
  REAL :: yua(mx_ua)
  REAL :: trnua(mx_ua)
  REAL :: elevua(mx_ua)
  REAL :: hgtua(nz_ua,mx_ua)
  INTEGER :: nlevsua(mx_ua)
  CHARACTER (LEN=5) :: stnua(mx_ua)
!
!-----------------------------------------------------------------------
!
!  Upper-air observation variables
!
!-----------------------------------------------------------------------
!
  REAL :: obsua(nvar_anx,nz_ua,mx_ua)
  REAL :: odifua(nvar_anx,nz_ua,mx_ua)
  REAL :: corua(nvar_anx,nz_ua,mx_ua)
  REAL :: oanxua(nvar_anx,nz_ua,mx_ua)
  REAL :: theua(nz_ua,mx_ua)
!
!-----------------------------------------------------------------------
!
!  Radar site variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnrad(mx_rad)
  INTEGER :: isrcrad(0:mx_rad)
  REAL :: latrad(mx_rad),lonrad(mx_rad)
  REAL :: elvrad(mx_rad)
!
!-----------------------------------------------------------------------
!
!  Radar observation variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: irad(mx_colrad)
  INTEGER :: nlevrad(mx_colrad)
  REAL :: latradc(mx_colrad)
  REAL :: lonradc(mx_colrad)
  REAL :: xradc(mx_colrad)
  REAL :: yradc(mx_colrad)
  REAL :: trnradc(mx_colrad)
  REAL :: distrad(mx_colrad)
  REAL :: uazmrad(mx_colrad)
  REAL :: vazmrad(mx_colrad)
  REAL :: hgtradc(nz_rdr,mx_colrad)
  REAL :: theradc(nz_rdr,mx_colrad)
  REAL :: obsrad(nvar_radin,nz_rdr,mx_colrad)
  REAL :: odifrad(nvar_rad,nz_rdr,mx_colrad)
  REAL :: corrad(nvar_rad,nz_rdr,mx_colrad)
  REAL :: oanxrad(nvar_rad,nz_rdr,mx_colrad)
!
!-----------------------------------------------------------------------
!
!  Retrieval radar variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=5) :: stnret(mx_ret)
  INTEGER :: isrcret(0:mx_ret)
  REAL :: latret(mx_ret)
  REAL :: lonret(mx_ret)
  REAL :: elvret(mx_ret)
!
!-----------------------------------------------------------------------
!
!  Retrieval observation variables
!
!-----------------------------------------------------------------------
!
  INTEGER :: iret(mx_colret)
  INTEGER :: nlevret(mx_colret)
  REAL :: latretc(mx_colret)
  REAL :: lonretc(mx_colret)
  REAL :: xretc(mx_colret)
  REAL :: yretc(mx_colret)
  REAL :: trnretc(mx_colret)
  REAL :: hgtretc(nz_ret,mx_colret)
  REAL :: theretc(nz_ret,mx_colret)
  REAL :: obsret(nvar_anx,nz_ret,mx_colret)
  REAL :: qrret(nz_ret,mx_colret)
  REAL :: odifret(nvar_anx,nz_ret,mx_colret)
  REAL :: corret(nvar_anx,nz_ret,mx_colret)
  REAL :: oanxret(nvar_anx,nz_ret,mx_colret)
!
!-----------------------------------------------------------------------
!
!  Namen de variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=6) :: var_sfc(nvar_sng)
  DATA var_sfc/ 't     ','td    ','dd    ','ff    ',                    &
                'urot  ','vrot  ','pstn  ','pmsl  ',                    &
                'alt   ','ceil  ','low   ','cover ',                    &
                'solar ','vis'/
  CHARACTER (LEN=6) :: var_ua(nvar_ua)
  DATA var_ua / 'press ',                                               &
                'temp  ','dewpt ','dd    ','ff    '/
  CHARACTER (LEN=6) :: var_anx(nvar_anx)
  DATA var_anx/ 'u     ','v     ',                                      &
                'press ','theta ','qv    '/
!
!-----------------------------------------------------------------------
!
!  Source-dependent parameters
!  Qsrc is the expected square error it is used for
!  setting the QC threshold (qclim) and for relative
!  weighting of observations.
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=80) :: srcback
  REAL :: hqback(nz_tab)
  INTEGER :: nlvqback
  REAL :: qback(nvar_anx,nz_tab)

  CHARACTER (LEN=80) :: srcsng_full(nsrc_sng)
  REAL :: qsrcsng(nvar_anx,nsrc_sng)

  CHARACTER (LEN=80) :: srcua_full(nsrc_ua)
  INTEGER :: nlvuatab(nsrc_ua)
  REAL :: huaqsrc(nz_tab,nsrc_ua)
  REAL :: qsrcua(nvar_anx,nz_tab,nsrc_ua)

  CHARACTER (LEN=80) :: srcrad_full(nsrc_rad)
  REAL :: qsrcrad(nvar_radin,nsrc_rad)

  CHARACTER (LEN=80) :: srcret_full(nsrc_ret)
  INTEGER :: nlvrttab(nsrc_ret)
  REAL :: hrtqsrc(nz_tab,nsrc_ret)
  REAL :: qsrcret(nvar_anx,nz_tab,nsrc_ret)
!
!-----------------------------------------------------------------------
!
!  Quality Control Parameters and Variables
!
!-----------------------------------------------------------------------
!
  REAL :: rmiss
  PARAMETER (rmiss=-99.)
!
  INTEGER :: qualrdsng(mx_sng,nvar_sng,ntime)
  INTEGER :: qualsng(nvar_anx,mx_sng)
  REAL :: qobsng(nvar_anx,mx_sng)
  REAL :: qcmulsng(nsrc_sng)
  REAL :: qcthrsng(nvar_anx,nsrc_sng)
  REAL :: barqclim(nvar_anx,nsrc_sng)
!
  INTEGER :: qualua(nvar_anx,nz_ua,mx_ua)
  REAL :: qobsua(nvar_anx,nz_ua,mx_ua)
  REAL :: qcmulua(nsrc_ua)
  REAL :: qcthrua(nvar_anx,nsrc_ua)
!
  INTEGER :: qualrad(nvar_rad,nz_rdr,mx_colrad)
  REAL :: qobsrad(nvar_rad,nz_rdr,mx_colrad)
  REAL :: qcmulrad(nsrc_rad)
  REAL :: qcthrrad(nvar_radin,nsrc_rad)
!
  INTEGER :: qualret(nvar_anx,nz_ret,mx_colret)
  REAL :: qobsret(nvar_anx,nz_ret,mx_colret)
  REAL :: qcmulret(nsrc_ret)
  REAL :: qcthrret(nvar_anx,nsrc_ret)
!
!-----------------------------------------------------------------------
!
!  Climin is the minimum possible value of each observed variable.
!  Climax is the maximum possible value of each observed variable.
!  Used for surface data only.
!
!-----------------------------------------------------------------------
!
  REAL :: climin(nvar_sng),climax(nvar_sng)
  DATA climin /  -50.,    -50.,    0.,    0.,                           &
                -100.,   -100.,  700.,  880.,                           &
                 880.,      0.,    0.,    0.,                           &
                   0.,      0./
  DATA climax /  125.,    125.,  360.,  100.,                           &
                 100.,    100., 1100., 1090.,                           &
                1090.,  30000.,30000.,    1.,                           &
                1500.,    150./
!
!-----------------------------------------------------------------------
!
!  Filenames and such
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=12)  :: suffix
  CHARACTER (LEN=256) :: froot
  CHARACTER (LEN=256) :: qclist
  CHARACTER (LEN=256) :: qcsave
  CHARACTER (LEN=256) :: stats        ! runname + '.lst'
  INTEGER :: istatus,jstatus,istat
  INTEGER :: nobsng,nobsrd(ntime)
  INTEGER :: i4timanx
  INTEGER :: lenfnm,maxsuf,lensuf,dotloc,mxroot,lenroot
  INTEGER :: iqclist,iqcsave,iwstat

  CHARACTER (LEN=256) :: status_file  ! runname + '.adasstat'
  INTEGER n_used_sng(nsrc_sng), n_used_ua(nsrc_sng)
  INTEGER jsta, klev, ngoodlev

!
!-----------------------------------------------------------------------
!
!  MPI bookkeeping
!
!-----------------------------------------------------------------------
!

  INTEGER :: indexsng(mx_sng)    ! indexes each data point according to
                                 ! which local proc domain it resides
  INTEGER, ALLOCATABLE :: ksng(:) ! Number of obs owned by each processor
  INTEGER :: ksngmax             ! Max "ksng" value.

  INTEGER :: indexua(mx_ua)      ! indexes each data point according to
                                 ! which local proc domain it resides
  INTEGER, ALLOCATABLE :: kua(:) ! Number of obs owned by each processor
  INTEGER :: kuamax              ! Max "kua" value.


  INTEGER :: indexrad(mx_rad)    ! indexes each data point according to
                                 ! which local proc domain it resides
  INTEGER :: indexret(mx_ret)    ! indexes each data point according to
                                 ! which local proc domain it resides

  INTEGER :: iproc               ! Radii of influence "i" direction
  INTEGER :: jproc               ! Radii of influence "j" direction

  INTEGER, ALLOCATABLE :: mpi_map(:,:) ! Map of communication entries
  INTEGER :: nmap       ! Number of entries in "mpi_map".

!
!-----------------------------------------------------------------------
!
!  Physical constants
!
!-----------------------------------------------------------------------
!
  REAL :: kts2ms,mb2pa,f2crat
  PARAMETER (kts2ms=0.514444,                                           &
             mb2pa=100.,                                                &
             f2crat=(5./9.))
!
!-----------------------------------------------------------------------
!
!  ptlapse is minimum potential temperature lapse rate to use in
!  superadiabatic check.  Used to ensure initial static stability.
!
!-----------------------------------------------------------------------

  REAL :: ptlapse
  PARAMETER (ptlapse = (1.0/4000.) )   ! deg K / m
!
!-----------------------------------------------------------------------
!
!  Function f_qvsat and inline directive for Cray PVP
!
!-----------------------------------------------------------------------
!
  REAL :: f_qvsat

!fpp$ expand (f_qvsat)
!!dir$ inline always f_qvsat
!
!-----------------------------------------------------------------------
!
!  Misc local variables
!
!-----------------------------------------------------------------------
!
  CHARACTER (LEN=8  ) :: rdsource
  CHARACTER (LEN=256) :: basdmpfn
  CHARACTER (LEN=80 ) :: header
  INTEGER :: i,j,k,ios,ktab,isrc,jsrc,ivar,ifile
  INTEGER :: grdbas,lbasdmpf,rbufsz
  INTEGER :: nobsua,ncolrad,ncolret,nmeso,nsao

  REAL :: tgrid,qvmin,qvsat,qsrcmax,rngsq
  REAL :: temp,tvbar,qvprt,qtot,pconst,pr1,pr2
!
  INTEGER :: ixrad(mx_rad),jyrad(mx_rad)

  INTEGER :: retqropt
  PARAMETER (retqropt=1)
  INTEGER :: imstat
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  nt = 1    ! Number of time levels of data
  ncat = 4  ! Number of correlation categories

!-----------------------------------------------------------------------
!  Set grid mode to non-nesting and grid index, mgrid, to 1.
!-----------------------------------------------------------------------

  nestgrd=0
  mgrid=1
 
!-----------------------------------------------------------------------
!  read in ARPS namelists
!-----------------------------------------------------------------------
 
  CALL initpara(nx,ny,nz,nzsoil,nstyps)

  IF (mp_opt > 0) THEN
    nxlg = (nx - 3) * nproc_x + 3
    nylg = (ny - 3) * nproc_y + 3
  ELSE
    nxlg = nx
    nylg = ny
  END IF

  IF (lbcopt == 2) THEN
    IF (myproc == 0) THEN
      WRITE (*,*) "INITADAS: resetting lbcopt to 1 & lateral bc's to 4"
    END IF
    lbcopt = 1
    ebc = 4
    wbc = 4
    nbc = 4
    sbc = 4
  END IF

!-----------------------------------------------------------------------
!  Read in adas namelist parameters
!-----------------------------------------------------------------------
!
  CALL initadas

  IF (mp_opt > 0) THEN
    CALL radinf(rlim)
!
!   See what our processor radius of influence is in each direction.
!
    iproc = INT( rlim / ( (nx-3) * dx )) + 1
    jproc = INT( rlim / ( (ny-3) * dy )) + 1

    IF (myproc == 0) THEN
      WRITE(6,*) 'Process radius of influence x & y ',iproc,jproc
    END IF
  ELSE
!
!   We'll allocate a trivial array.
!
    iproc = 1
    jproc = 1
  ENDIF

  IF(incrdmp > 0 ) THEN
    nxndg=nx
    nyndg=ny
    nzndg=nz
  ELSE
    nxndg=1
    nyndg=1
    nzndg=1
  END IF
!
!-----------------------------------------------------------------------
!
!  Allocate adas arrays
!
!-----------------------------------------------------------------------
!
  ALLOCATE(x(nx),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:x")
  ALLOCATE(y(ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:y")
  ALLOCATE(z(nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:z")

  CALL check_alloc_status(istatus, "adas:y")
  ALLOCATE(hterain(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:hterain")
  ALLOCATE(mapfct (nx,ny,8),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:mapfct")

  ALLOCATE(zp  (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:zp")
  ALLOCATE(zpsoil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:zpsoil")
  ALLOCATE(j1  (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j1")
  ALLOCATE(j2  (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j2")
  ALLOCATE(j3  (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j3")
  ALLOCATE(j3soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j3soil")
  ALLOCATE(aj3x(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:aj3x")
  ALLOCATE(aj3y(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:aj3y")
  ALLOCATE(aj3z(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:aj3z")
  ALLOCATE(j3inv(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j3inv")
  ALLOCATE(j3soilinv(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:j3soilinv")

  ALLOCATE(u    (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:u")
  ALLOCATE(v    (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:v")
  ALLOCATE(w    (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:w")
  ALLOCATE(wcont(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wcont")
  ALLOCATE(ptprt(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ptprt")
  ALLOCATE(pprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pprt")

  ALLOCATE(qv   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qv")
  ALLOCATE(qc   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qc")
  ALLOCATE(qr   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qr")
  ALLOCATE(qi   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qi")
  ALLOCATE(qs   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qs")
  ALLOCATE(qh   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qh")
  ALLOCATE(tke  (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tke")

  ALLOCATE(ubar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ubar")
  ALLOCATE(vbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vbar")
  ALLOCATE(ptbar(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ptbar")
  ALLOCATE(pbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pbar")
  ALLOCATE(rhostr(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:rhostr")
  ALLOCATE(qvbar(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qvbar")

  ALLOCATE(udteb(ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:udteb")
  ALLOCATE(udtwb(ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:udtbw")
  ALLOCATE(vdtnb(nx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vdtnb")
  ALLOCATE(vdtsb(nx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vdtsb")

  ALLOCATE(pdteb(ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pdteb")
  ALLOCATE(pdtwb(ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pdtwb")
  ALLOCATE(pdtnb(nx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pdtnb")
  ALLOCATE(pdtsb(nx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pdtsb")

  ALLOCATE(trigs1(3*(nx-1)/2+1),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:trigs1")
  ALLOCATE(trigs2(3*(ny-1)/2+1),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:trigs2")
  ALLOCATE(ifax1(13),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ifax1")
  ALLOCATE(ifax2(13),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ifax2")
   
  ALLOCATE(vwork1(nx+1,ny+1),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vwork1")
  ALLOCATE(vwork2(ny,nx+1),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vwork2")

  ALLOCATE(wsave1(3*(ny-1)+15),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wsave1")
  ALLOCATE(wsave2(3*(nx-1)+15),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wsave2")

  ALLOCATE(ppi   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ppi")
  ALLOCATE(csndsq(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:csndsq")

  ALLOCATE(radfrc(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:radfrc")
  ALLOCATE(radsw (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:radsw")
  ALLOCATE(rnflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:rnflx")
  ALLOCATE(radswnet (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:radswnet")
  ALLOCATE(radlwin (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:radlwin")

  ALLOCATE(soiltyp(nx,ny,nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:soiltyp")
  ALLOCATE(stypfrct(nx,ny,nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:stypfrct")
  ALLOCATE(vegtyp (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vegtyp")
  ALLOCATE(lai    (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:lai")
  ALLOCATE(roufns (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:roufns")
  ALLOCATE(veg    (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:veg")

  ALLOCATE(qvsfc  (nx,ny,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qvsfc")
  ALLOCATE(tsoil  (nx,ny,nzsoil,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tsoil")
  ALLOCATE(qsoil  (nx,ny,nzsoil,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qsoil")
  ALLOCATE(wetcanp(nx,ny,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wetcanp")
  ALLOCATE(snowdpth(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:snowdpth")

  ALLOCATE(ptcumsrc(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ptcumsrc")
  ALLOCATE(qcumsrc (nx,ny,nz,5),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qcumsrc")
  ALLOCATE(w0avg   (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:w0avg")
  ALLOCATE(nca    (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:nca")
  ALLOCATE(kfraincv (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:kfraincv")
  ALLOCATE(cldefi (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:cldefi")
  ALLOCATE(xland  (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:xland")
  ALLOCATE(bmjraincv (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:bmjraincv")
  ALLOCATE(raing  (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:raing")
  ALLOCATE(rainc  (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:rainc")
  ALLOCATE(prcrate(nx,ny,4),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:prcrate")

  ALLOCATE(usflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:usflx")
  ALLOCATE(vsflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vsflx")
  ALLOCATE(ptsflx(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ptsflx")
  ALLOCATE(qvsflx(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qvsflx")

  ALLOCATE(uincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:uincr")
  ALLOCATE(vincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:vincr")
  ALLOCATE(wincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wincr")
  ALLOCATE(pincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:pincr")
  ALLOCATE(ptincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ptincr")
  ALLOCATE(qvincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qvincr")
  ALLOCATE(qcincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qcincr")
  ALLOCATE(qrincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qrincr")
  ALLOCATE(qiincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qiincr")
  ALLOCATE(qsincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qsincr")
  ALLOCATE(qhincr(nxndg,nyndg,nzndg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:qhincr")

  ALLOCATE(knt(nvar_anx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:knt")
  ALLOCATE(rngsqi(nvar_anx),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:rngsqi")
  ALLOCATE(wgtsum(nvar_anx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:wgtsum")
  ALLOCATE(zsum(nvar_anx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:zsum")
  ALLOCATE(sqsum(nvar_anx,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:sqsum")

  ALLOCATE(xs(nx),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:xs")
  ALLOCATE(ys(ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ys")

  ALLOCATE(xslg(nxlg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:xslg")
  ALLOCATE(yslg(nylg),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:yslg")

  ALLOCATE(zs(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:zs")
  ALLOCATE(latgr(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:latgr")
  ALLOCATE(longr(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:longr")

  ALLOCATE(tem1soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem1soil")
  ALLOCATE(tem2soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem2soil")
  ALLOCATE(tem3soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem3soil")
  ALLOCATE(tem4soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem4soil")
  ALLOCATE(tem5soil(nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem5soil")

  ALLOCATE(tem1(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem1")
  ALLOCATE(tem2(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem2")
  ALLOCATE(tem3(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem3")
  ALLOCATE(tem4(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem4")
  ALLOCATE(tem5(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem5")
  ALLOCATE(tem6(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem6")
  ALLOCATE(tem7(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem7")
  ALLOCATE(tem8(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem8")
  ALLOCATE(tem9(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem9")
  ALLOCATE(tem10(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem10")
  ALLOCATE(tem11(nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:tem11")
  ALLOCATE(ibegin(ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:ibegin")
  ALLOCATE(iend(ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:iend")

  ALLOCATE(anx(nx,ny,nz,nvar_anx),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:anx")

  ALLOCATE(xcor(ncat,ncat),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:xcor")
  ALLOCATE(icatg(nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:icatg")

  nmap = ( 2 * iproc + 1 ) * ( 2 * jproc + 1 )
  ALLOCATE(mpi_map(nmap,2),STAT=istatus)
  CALL check_alloc_status(istatus, "adas:mpi:map")

  IF (myproc == 0) WRITE (*,*) "Finished allocating arrays"
 
!-----------------------------------------------------------------------
! Initialize the allocated arrays to zero.
!-----------------------------------------------------------------------

  x=0.0
  y=0.0
  z=0.0

  hterain=0.0
  mapfct =0.0

  zp  =0.0
  zpsoil  =0.0
  j1  =0.0
  j2  =0.0
  j3  =0.0
  j3soil  =0.0
  aj3x=0.0
  aj3y=0.0
  aj3z=0.0
  j3inv=0.0
  j3soilinv=0.0

  u    =0.0
  v    =0.0
  w    =0.0
  wcont=0.0
  ptprt=0.0
  pprt =0.0

  qv   =0.0
  qc   =0.0
  qr   =0.0
  qi   =0.0
  qs   =0.0
  qh   =0.0
  tke  =0.0

  ubar =0.0
  vbar =0.0
  ptbar=0.0
  pbar =0.0
  rhostr=0.0
  qvbar=0.0

  udteb=0.0
  udtwb=0.0
  vdtnb=0.0
  vdtsb=0.0

  pdteb=0.0
  pdtwb=0.0
  pdtnb=0.0
  pdtsb=0.0

  trigs1=0.0
  trigs2=0.0
  ifax1=0.0
  ifax2=0.0
   
  vwork1=0.0
  vwork2=0.0

  wsave1=0.0
  wsave2=0.0

  ppi   =0.0
  csndsq=0.0

  radfrc=0.0
  radsw =0.0
  rnflx =0.0
  radswnet =0.0
  radlwin =0.0

  soiltyp=0.0
  stypfrct=0.0
  vegtyp =0.0
  lai    =0.0
  roufns =0.0
  veg    =0.0

  qvsfc  =0.0
  tsoil  =0.0
  qsoil  =0.0
  wetcanp=0.0
  snowdpth=0.0

  ptcumsrc=0.0
  qcumsrc =0.0
  w0avg   =0.0
  nca    =0.0
  kfraincv =0.0
  cldefi = 0.0
  xland = 0.0
  bmjraincv = 0.0
  raing  =0.0
  rainc  =0.0
  prcrate=0.0

  usflx =0.0
  vsflx =0.0
  ptsflx=0.0
  qvsflx=0.0

  knt=0.0
  rngsqi=0.0
  wgtsum=0.0
  zsum=0.0
  sqsum=0.0

  xs=0.0
  ys=0.0
  xslg = 0.0
  yslg = 0.0
  zs=0.0
  latgr=0.0
  longr=0.0

  tem1=0.0
  tem2=0.0
  tem3=0.0
  tem4=0.0
  tem5=0.0
  tem6=0.0
  tem7=0.0
  tem8=0.0
  tem9=0.0
  tem10=0.0

  qsrcsng = 0.0

  ibegin=0
  iend=0

  anx=0.0

  xcor=0.0
  icatg=0.0

!
!-----------------------------------------------------------------------
!
!  Read in quality control info.  Most of the information will not be
!  broadcast, as processor 0 will handle pre-processing of obs before
!  the data gets sent to the other processors.
!
!-----------------------------------------------------------------------
!

!
!-----------------------------------------------------------------------
!
!  Set expected _squared_ background error for each variable
!  This will depend on the particular background field used,
!  season, age of forecast, etc.
!
!-----------------------------------------------------------------------
!

  IF (myproc == 0) THEN
     WRITE(6,'(/,a,a)') ' Reading ', TRIM(backerrfil)
     OPEN(4,FILE=trim(backerrfil),STATUS='old')
     READ(4,'(a80)') srcback
     READ(4,'(a80)') header
     WRITE(6,'(//,a,/a)') 'Background Std Error for',srcback
     WRITE(6,'(1x,a)')                                                  &
         '   k    hgt(m)  u(m/s)  v(m/s) pres(mb) temp(K)  RH(%)'
     DO ktab=1,nz_tab
       READ(4,*,iostat=istat) hqback(ktab),                             &
                qback(3,ktab),                                          &
                qback(4,ktab),                                          &
                qback(5,ktab),                                          &
                qback(1,ktab),                                          &
                qback(2,ktab)
       IF( istat /= 0 ) EXIT
       WRITE(6,'(1x,i4,f10.2,5f8.2)') ktab,hqback(ktab),                &
                               (qback(ivar,ktab),ivar=1,5)
       qback(3,ktab)=100.*qback(3,ktab)
       qback(5,ktab)=0.01*qback(5,ktab)
     END DO
     nlvqback=ktab-1
     CLOSE(4)

     DO jsrc=1,nsrc_sng
        IF(srcsng(jsrc) /= 'NULL') THEN
           WRITE(6,'(/,a,a)') ' Reading ', TRIM(sngerrfil(jsrc))
           OPEN(4,FILE=trim(sngerrfil(jsrc)),STATUS='old')
           READ(4,'(a8)') rdsource
           IF(rdsource /= srcsng(jsrc)) THEN
              WRITE(6,'(a,i4,a,a,a,a,a)')                               &
              ' Mismatch of source names',jsrc,                         &
              ' read ',rdsource,' expected ',srcsng(jsrc)
              CALL arpsstop("mismatch",1)
           END IF
           READ(4,'(a80)') srcsng_full(jsrc)
           READ(4,*) qcmulsng(jsrc)
           READ(4,'(a80)') header
           READ(4,*) qsrcsng(3,jsrc),                                   &
                     qsrcsng(4,jsrc),                                   &
                     qsrcsng(5,jsrc),                                   &
                     qsrcsng(1,jsrc),                                   &
                     qsrcsng(2,jsrc)
           WRITE(6,'(//,a,a,/a)') 'Single-level std error for ',        &
                            srcsng(jsrc),srcsng_full(jsrc)
           WRITE(6,'(a,f5.1)') ' QC multiplier: ',qcmulsng(jsrc)
           WRITE(6,'(1x,a)')                                            &
               '   u (m/s)  v (m/s)  pres(mb) temp(K) RH(%)'
           WRITE(6,'(1x,5f8.2)') (qsrcsng(ivar,jsrc),ivar=1,5)
           qsrcsng(3,jsrc)=100.*qsrcsng(3,jsrc)
           qsrcsng(5,jsrc)=0.01*qsrcsng(5,jsrc)
           CLOSE(4)
        ELSE
          DO k=1,npass
            iusesng(jsrc,k) = 0
          END DO
        END IF
     END DO

     DO jsrc=1,nsrc_ua
        IF(srcua(jsrc) /= 'NULL') THEN
           WRITE(6,'(/,a,a)') ' Reading ', TRIM(uaerrfil(jsrc))
           OPEN(4,FILE=trim(uaerrfil(jsrc)),STATUS='old')
           READ(4,'(a8)') rdsource
           IF(rdsource /= srcua(jsrc)) THEN
              WRITE(6,'(a,i4,a,a,a,a,a)')                               &
                 ' Mismatch of source names',jsrc,                      &
                 ' read ',rdsource,' expected ',srcua(jsrc)
              CALL arpsstop("mismatch",1)
           END IF
           READ(4,'(a80)') srcua_full(jsrc)
           READ(4,*) qcmulua(jsrc)
           READ(4,'(a80)') header
           WRITE(6,'(//,a,a,/a)') 'UA data std error for ',             &
                            srcua(jsrc),srcua_full(jsrc)
           WRITE(6,'(a,f5.1)') ' QC multiplier: ',qcmulua(jsrc)
           WRITE(6,'(1x,a)')                                            &
              '   k    hgt(m)  u(m/s)  v(m/s) pres(mb) temp(K)  RH(%)'
           DO ktab=1,nz_tab
              READ(4,*,iostat=istat) huaqsrc(ktab,jsrc),                &
                              qsrcua(3,ktab,jsrc),                      &
                              qsrcua(4,ktab,jsrc),                      &
                              qsrcua(5,ktab,jsrc),                      &
                              qsrcua(1,ktab,jsrc),                      &
                              qsrcua(2,ktab,jsrc)
              IF( istat /= 0 ) EXIT
              WRITE(6,'(1x,i4,f10.2,5f8.2)') ktab,huaqsrc(ktab,jsrc),   &
                 (qsrcua(ivar,ktab,jsrc),ivar=1,5)
              qsrcua(3,ktab,jsrc)=100.*qsrcua(3,ktab,jsrc)
              qsrcua(5,ktab,jsrc)=0.01*qsrcua(5,ktab,jsrc)
           END DO
           nlvuatab(jsrc)=ktab-1
           CLOSE(4)
        ELSE
          DO k=1,npass
            iuseua(jsrc,k) = 0
          END DO
        END IF
     END DO

     DO jsrc=1,nsrc_rad
        IF(srcrad(jsrc) /= 'NULL') THEN
          WRITE(6,'(/,a,a)') ' Reading ', TRIM(raderrfil(jsrc))
          OPEN(4,FILE=trim(raderrfil(jsrc)),STATUS='old')
          READ(4,'(a8)') rdsource
          IF(rdsource /= srcrad(jsrc)) THEN
            WRITE(6,'(a,i4,a,a,a,a,a)')                                  &
               ' Mismatch of source names',jsrc,                         &
               ' read ',rdsource,' expected ',srcrad(jsrc)
            CALL arpsstop("mismatch",1)
          END IF
          READ(4,'(a80)') srcrad_full(jsrc)
          READ(4,*) qcmulrad(jsrc)
          READ(4,'(a80)') header
          READ(4,*) qsrcrad(1,jsrc),                                    &
                    qsrcrad(2,jsrc),                                    &
                    qsrcrad(3,jsrc)
          WRITE(6,'(//,a,a,/a)') 'Radar data std error for ',           &
                          srcrad(jsrc),srcrad_full(jsrc)
          WRITE(6,'(a,f5.1)') ' QC multiplier: ',qcmulrad(jsrc)
          WRITE(6,'(1x,a)')                                             &
             '    ref(dBz) Vrad(m/s) SpWid(m/s)'
          WRITE(6,'(1x,4f8.2)')                                         &
             (qsrcrad(ivar,jsrc),ivar=1,nvar_radin)
          CLOSE(4)
           qsrcsng(5,jsrc)=0.01*qsrcsng(5,jsrc)
           CLOSE(4)
        ELSE
          DO k=1,npass
            iuserad(jsrc,k) = 0
          END DO
        END IF
     END DO

     DO jsrc=1,nsrc_ret
        IF(srcret(jsrc) /= 'NULL') THEN
           WRITE(6,'(/,a,a)') ' Reading ', TRIM(reterrfil(jsrc))
           OPEN(4,FILE=trim(reterrfil(jsrc)),STATUS='old')
           READ(4,'(a8)') rdsource
           IF(rdsource /= srcret(jsrc)) THEN
             WRITE(6,'(a,i4,a,a,a,a,a)')                                 &
                ' Mismatch of source names',jsrc,                        &
                ' read ',rdsource,' expected ',srcret(jsrc)
             CALL arpsstop("mismatch",1)
           END IF
           READ(4,'(a80)') srcret_full(jsrc)
           READ(4,*) qcmulret(jsrc)
           READ(4,'(a80)') header
           WRITE(6,'(//,a,a,/a)') 'Retrieval std error for ',                &
                               srcret(jsrc),srcret_full(jsrc)
           WRITE(6,'(a,f5.1)') ' QC multiplier: ',qcmulrad(jsrc)
           WRITE(6,'(1x,a)')                                                 &
               '   k    hgt(m)  u(m/s)  v(m/s) pres(mb) temp(K)  RH(%)'
           DO ktab=1,nz_tab
              READ(4,*,iostat=istat) hrtqsrc(ktab,jsrc),                     &
                              qsrcret(3,ktab,jsrc),                          &
                              qsrcret(4,ktab,jsrc),                          &
                              qsrcret(5,ktab,jsrc),                          &
                              qsrcret(1,ktab,jsrc),                          &
                              qsrcret(2,ktab,jsrc)
              IF( istat /= 0 ) EXIT
              WRITE(6,'(1x,i4,f10.2,5f8.2)') ktab,hrtqsrc(ktab,jsrc),         &
                              (qsrcret(ivar,ktab,jsrc),ivar=1,5)
              qsrcret(3,ktab,jsrc)=100.*qsrcret(3,ktab,jsrc)
              qsrcret(5,ktab,jsrc)=0.01*qsrcret(5,ktab,jsrc)
           END DO
           nlvrttab(jsrc)=ktab-1
           CLOSE(4)
        ELSE
          DO k=1,npass
            iuseret(jsrc,k) = 0
          END DO
        END IF
     END DO

!
!-----------------------------------------------------------------------
!
!  Change standard error to standard error variance by squaring
!  Calculate quality control thresholds
!
!-----------------------------------------------------------------------
!
    DO ktab=1,nlvqback
      DO ivar=1,nvar_anx
        qback(ivar,ktab)=qback(ivar,ktab)*qback(ivar,ktab)
      END DO
    END DO
!
    DO isrc=1,nsrc_sng
      DO ivar=1,nvar_anx
        qsrcsng(ivar,isrc)=qsrcsng(ivar,isrc)*qsrcsng(ivar,isrc)
        qcthrsng(ivar,isrc)=qcmulsng(isrc)*                               &
                         SQRT(qback(ivar,1)+qsrcsng(ivar,isrc))
        barqclim(ivar,isrc)=qcmulsng(isrc)*SQRT(qsrcsng(ivar,isrc))
      END DO
      qcthrsng(iqv,isrc)=min(qcthrsng(iqv,isrc),0.75)
      barqclim(iqv,isrc)=min(barqclim(iqv,isrc),0.75)
    END DO
!
    DO isrc=1,nsrc_ua
      DO ivar=1,nvar_anx
        qsrcmax=0.
        DO ktab=1,nlvuatab(isrc)
          qsrcua(ivar,ktab,isrc) =                                        &
              qsrcua(ivar,ktab,isrc)*qsrcua(ivar,ktab,isrc)
          qsrcmax=AMAX1(qsrcmax,qsrcua(ivar,ktab,isrc))
        END DO
        qcthrua(ivar,isrc)=qcmulua(isrc)*                                 &
                           SQRT(qback(ivar,1)+qsrcmax)
      END DO
      qcthrua(iqv,isrc)=min(qcthrua(iqv,isrc),0.75)
    END DO
!
    DO isrc=1,nsrc_rad
      DO ivar=1,nvar_radin
        qsrcrad(ivar,isrc) =                                              &
            qsrcrad(ivar,isrc)*qsrcrad(ivar,isrc)
        qcthrrad(ivar,isrc)=qcmulrad(isrc)*                               &
                            SQRT(qback(ivar,1)+qsrcrad(ivar,isrc))
      END DO
    END DO
!
    DO isrc=1,nsrc_ret
      DO ivar=1,nvar_anx
        qsrcmax=0.
        DO ktab=1,nlvrttab(isrc)
          qsrcret(ivar,ktab,isrc) =                                       &
              qsrcret(ivar,ktab,isrc)*qsrcret(ivar,ktab,isrc)
          qsrcmax=AMAX1(qsrcmax,qsrcret(ivar,ktab,isrc))
        END DO
        qcthrret(ivar,isrc)=qcmulret(isrc)*                               &
                            SQRT(qback(ivar,1)+qsrcmax)
      END DO
      qcthrret(iqv,isrc)=min(qcthrret(iqv,isrc),0.75)
    END DO
  END IF

!
!  Broadcast read variables to all procs.  Some are dead, so we keep them
!  that way.  Others are only used by processor zero initially.
!
!  Also broadcast variables that may have been updated.
!

  CALL mpupdater(hqback, nz_tab)
  CALL mpupdater(qback, (nvar_anx*nz_tab))
  CALL mpupdatei(nlvqback, 1) 

  CALL mpupdatec(srcsng, (8*nsrc_sng))
  CALL mpupdater(qcthrsng, (nvar_anx*nsrc_sng))

  CALL mpupdater(qcthrua, (nvar_anx*nsrc_ua))

  CALL mpupdater(qcthrrad, (nvar_radin*nsrc_rad))

  CALL mpupdater(qcthrret, (nvar_anx*nsrc_ret))

  CALL mpupdatei(iusesng,(nsrc_sng+1)*mx_pass)
  CALL mpupdatei(iuseua,(nsrc_ua+1)*mx_pass)
  CALL mpupdatei(iuserad,(nsrc_rad+1)*mx_pass)
  CALL mpupdatei(iuseret,(nsrc_ret+1)*mx_pass)

  CALL make_mpi_map(mpi_map,nmap,iproc,jproc,nx,ny)

!
!-----------------------------------------------------------------------
!
!  Set cross-correlations between numerical categories.
!  Roughly 1=clear,2=some evidence of outflow,3=precip,4=conv precip
!  This could be read in as a table.
!
!-----------------------------------------------------------------------
!
  DO j=1,ncat
    DO i=1,ncat
      xcor(i,j)=1.0-(IABS(i-j))*0.25
    END DO
  END DO
!
!-----------------------------------------------------------------------
!
!  Initialize grids, forming first guess fields based on
!  the model initial option specified in the ARPS init file.
!
!-----------------------------------------------------------------------
!

  CALL initgrdvar(nx,ny,nz,nzsoil,1,nstyps,1,                           &
                  x,y,z,zp,zpsoil,hterain,mapfct,                       &
                  j1,j2,j3,j3soil,aj3x,aj3y,aj3z,j3inv,j3soilinv,       &
                  u,v,w,wcont,ptprt,pprt,qv,qc,qr,qi,qs,qh,tke,         &
                  udteb, udtwb, vdtnb, vdtsb,                           &
                  pdteb,pdtwb ,pdtnb ,pdtsb,                            &
                  trigs1,trigs2,ifax1,ifax2,                            &
                  wsave1,wsave2,vwork1,vwork2,                          &
                  ubar,vbar,ptbar,pbar,tem10,tem10,                     &
                  rhostr,tem10,qvbar,ppi,csndsq,                        &
                  soiltyp,stypfrct,vegtyp,lai,roufns,veg,               &
                  tsoil,qsoil,wetcanp,snowdpth,qvsfc,                   &
                  ptcumsrc,qcumsrc,w0avg,nca,kfraincv,                  &
                  cldefi,xland,bmjraincv,                               &
                  raing,rainc,prcrate,exbcbuf,                          &
                  radfrc,radsw,rnflx,radswnet,radlwin,                  &
                  usflx,vsflx,ptsflx,qvsflx,                            &
                  tem1soil,tem2soil,tem3soil,tem4soil,tem5soil,         &
                  tem1,tem2,tem3,tem4,tem5,                             &
                  tem6,tem7,tem8,tem9)
!
!-----------------------------------------------------------------------
!
!  Deallocate some arrays needed only for initgrdvar
!
!-----------------------------------------------------------------------
!
  DEALLOCATE(ptcumsrc)
  DEALLOCATE(qcumsrc)
  DEALLOCATE(w0avg)
  DEALLOCATE(kfraincv)
  DEALLOCATE(nca)
  DEALLOCATE(cldefi)
  DEALLOCATE(xland)
!
!-----------------------------------------------------------------------
!
!  Set location of scalar fields.
!
!-----------------------------------------------------------------------
!
  CALL xytoll(nx,ny,x,y,latgr,longr)

  DO i=1,nx-1
    xs(i)=0.5*(x(i)+x(i+1))
  END DO
  xs(nx)=2.0*xs(nx-1)-xs(nx-2)
  DO j=1,ny-1
    ys(j)=0.5*(y(j)+y(j+1))
  END DO
  ys(ny)=2.0*ys(ny-1)-ys(ny-2)
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
        zs(i,j,k)=0.5*(zp(i,j,k)+zp(i,j,k+1))
      END DO
    END DO
  END DO
  DO i=1,nx-1
    DO j=1,ny-1
      zs(i,j,nz)=2.*zs(i,j,nz-1)-zs(i,j,nz-2)
    END DO
  END DO

!
!-----------------------------------------------------------------------
!
! In the MPI world, some subroutines will need to know characteristics
! of the large grid.  To simply later subroutine calls (one call not two
! surrounded by IF/ELSE/ENDIF, everybody that always needs the large
! grid will use the large grid variables.  Large grid info is used by
! early decision making when determining what obs are needed.
!
!-----------------------------------------------------------------------
!

  IF (mp_opt > 0 ) THEN
     CALL mpimerge1dx(xs,nx,xslg)
     CALL mpimerge1dy(ys,ny,yslg)

     CALL mpupdater(xslg,nxlg)
     CALL mpupdater(yslg,nylg)

  ELSE
     xslg = xs
     yslg = ys

  END IF

  CALL ctim2abss( year,month,day,hour,minute,second, i4timanx)
!
!-----------------------------------------------------------------------
!
!  Identify the background field correlation category for
!  each 2-d point.   This is based on precip rate, cumulus
!  parameterization switch, and surface relative humidity.
!
!-----------------------------------------------------------------------
!
  CALL setcat(nx,ny,nz,ccatopt,zs,                                      &
              ptprt,pprt,qv,qc,qr,qi,qs,qh,                             &
              ptbar,pbar,                                               &
              prcrate,icatg)
!
!-----------------------------------------------------------------------
!
!  Load "background fields" for analysis
!  Note, analysis is done at scalar points
!
!-----------------------------------------------------------------------
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
!
!  Look at how "u" and "v" are defined as to whether we need to pass data
!  to obtain the correct average of "u" and "v" at nx-1 and ny-1.
!
        anx(i,j,k,1)=0.5*(u(i,j,k)+u(i+1,j,k))
        anx(i,j,k,2)=0.5*(v(i,j,k)+v(i,j+1,k))
        anx(i,j,k,3)=pbar(i,j,k)+pprt(i,j,k)
        anx(i,j,k,4)=ptbar(i,j,k)+ptprt(i,j,k)
        anx(i,j,k,5)=qv(i,j,k)
      END DO
    END DO
  END DO

  IF (mp_opt > 0) THEN
    DO k=1,nvar_anx
      IF (k == 1) THEN                                           ! u
        j = 1
      ELSE IF (k == 2) THEN                                      ! v
        j = 2
      ELSE                                                       ! not u or v
        j = 0
      END IF
      CALL mpsendrecv2dew(anx(1,1,1,k),nx,ny,nz,ebc,wbc,j,tem1)
      CALL mpsendrecv2dns(anx(1,1,1,k),nx,ny,nz,nbc,sbc,j,tem1)
    END DO
  END IF

!-----------------------------------------------------------------------
!
!  Save background fields on staggered grid in the increment
!  arrays.
!
!  PROBABLY NEEDS MPI WORK!
!
!-----------------------------------------------------------------------
!
  IF(incrdmp > 0) THEN
    CALL incrsave(nx,ny,nz,nxndg,nyndg,nzndg,                           &
                  u,v,w,pprt,ptprt,qv,                                  &
                  qc,qr,qi,qs,qh,                                       &
                  uincr,vincr,wincr,pincr,ptincr,qvincr,                &
                  qcincr,qrincr,qiincr,qsincr,qhincr,                   &
                  istatus)
  END IF
!
!-----------------------------------------------------------------------
!
!  Filename creation
!
!-----------------------------------------------------------------------
!

  iwstat = 0
  IF (myproc == 0) THEN
    WRITE(stats,'(a,a)') runname(1:lfnkey),'.lst'
    CALL getunit(iwstat)
    PRINT *, 'Writing ', TRIM(stats)
    OPEN(iwstat,IOSTAT=ios,FILE=trim(stats),STATUS='unknown')
    IF(ios /= 0) iwstat=0
  END IF

  IF(ios /= 0) iwstat=0

  maxsuf=LEN(suffix)
  mxroot=LEN(froot)
  nobsng=0

  iqclist = 0
  iqcsave = 0

!
!  Read and preprocess the single level data, all done on processor 0.
!  Broadcast the data to the rest of the ADAS world.
!

  IF (myproc == 0) THEN
    DO ifile=1,nsngfil
      PRINT *, 'Processing file ', ifile, ' ', TRIM(sngfname(ifile))
      lenfnm=LEN(sngfname(ifile))
      CALL strlnth(sngfname(ifile),lenfnm)
      CALL exsufx(sngfname(ifile),lenfnm,suffix,maxsuf,dotloc,lensuf)

      IF(lensuf == 3. .AND. suffix(1:3) == 'lso') THEN

        CALL exfroot(sngfname(ifile),lenfnm,froot,mxroot,lenroot)
        WRITE(qclist,'(a,a)') froot(1:lenroot),'.sqc'
        WRITE(qcsave,'(a,a)') froot(1:lenroot),'.lsq'
!
!-----------------------------------------------------------------------
!
!  Open the files for listing QC info
!  To suppress listing set the unit numbers to zero
!
!-----------------------------------------------------------------------
!

        CALL getunit(iqclist)
        PRINT *, 'Opening qclist: ', TRIM(qclist)
        OPEN(iqclist,IOSTAT=ios,FILE=trim(qclist),STATUS='unknown')
        IF(ios /= 0) iqclist=0
        CALL getunit(iqcsave)
        PRINT *, 'Opening qclist: ', TRIM(qcsave)
        OPEN(iqcsave,IOSTAT=ios,FILE=trim(qcsave),STATUS='unknown')
        IF(ios /= 0) iqcsave=0

!
!-----------------------------------------------------------------------
!
!  Read surface data, QC and convert units.
!
!-----------------------------------------------------------------------
!

        rngsq=sfcqcrng*sfcqcrng
        IF (myproc == 0) PRINT *, 'Calling prepsfcobs'
        CALL prepsfcobs(ntime,mx_sng,                                     &
            nvar_sng,nvar_anx,nsrc_sng,nobsng,ipres,iptmp,iqv,            &
            sngfname(ifile),sngtmchk(ifile),blackfil,                     &
            var_sfc,var_anx,srcsng,qsrcsng,                               &
            rmiss,iqspr,sprdist,nobsrd,timesng,                           &
            stnsng,csrcsng,isrcsng,latsng,lonsng,hgtsng,xsng,ysng,        &
            nxlg,nylg,xslg,yslg,                                          &
            wx,kloud,idp3,store_emv,store_hgt,store_amt,                  &
            obrdsng,obsng,qualrdsng,qobsng,qualsng,                       &
            ival,climin,climax,                                           &
            rngsq,klim,wlim,qcthrsng,barqclim,                            &
            knt,wgtsum,zsum,sqsum,iqclist,iqcsave,jstatus)

        IF(iqclist /= 0) THEN
          CLOSE(iqclist)
          CALL retunit(iqclist)
        END IF
        IF(iqcsave /= 0) THEN
          CLOSE(iqcsave)
          CALL retunit(iqcsave)
        END IF

      ELSE

!
!-----------------------------------------------------------------------
!
!  Read other single-level data and convert units.  Note that we are
!  using the global domain here, even if we're in MPI mode, as only
!  processor 0 is doing this.
!
!-----------------------------------------------------------------------
!
        IF (myproc == 0) PRINT *, 'Calling prepsglobs'
        CALL prepsglobs(mx_sng,ntime,srcsng,nsrc_sng,                   &
              sngfname(ifile),stnsng,latsng,lonsng,xsng,ysng,           &
              hgtsng,obsng,qobsng,qualsng,isrcsng,qsrcsng,              &
              csrcsng,nxlg,nylg,nz,nvar_anx,anx,xslg,yslg,zp,           &
              tem1,tem2,tem3,tem4,tem5,tem6,                            &
              rmiss,nobsng,istatus)
      END IF
    END DO
  END IF ! myproc == 0

!
!-----------------------------------------------------------------------
!
!  MPI issues.  Broadcast the number of data points, then the data.  If
!  there are no data values, we don't waste anyone's time.
!
!-----------------------------------------------------------------------
!

  IF (mp_opt > 0) THEN
    CALL mpupdatei(nobsng,1)
    IF (nobsng > 0) THEN
      CALL mpupdatei(timesng,mx_sng*ntime)
      CALL mpupdatec(stnsng,mx_sng*ntime*5)
      CALL mpupdatec(csrcsng,mx_sng*ntime*8)
      CALL mpupdatei(isrcsng,mx_sng)
      CALL mpupdater(latsng,mx_sng*ntime)
      CALL mpupdater(lonsng,mx_sng*ntime)
      CALL mpupdater(hgtsng,mx_sng*ntime)
      CALL mpupdater(xsng,mx_sng)
      CALL mpupdater(ysng,mx_sng)
      CALL mpupdatec(wx,mx_sng*ntime*8)
      CALL mpupdatei(kloud,mx_sng*ntime)
      CALL mpupdatei(idp3,mx_sng*ntime)
      CALL mpupdatec(store_emv,mx_sng*5*ntime)
      CALL mpupdater(store_hgt,mx_sng*5*ntime)
      CALL mpupdatec(store_amt,mx_sng*5*ntime*4)
      CALL mpupdater(obrdsng,mx_sng*nvar_sng*ntime)
      CALL mpupdater(obsng,nvar_anx*mx_sng)
      CALL mpupdater(qobsng,nvar_anx*mx_sng)
      CALL mpupdatei(qualsng,nvar_anx*mx_sng)
      CALL mpupdater(knt,nvar_anx*nz)
      CALL mpupdater(wgtsum,nvar_anx*nz)
      CALL mpupdater(zsum,nvar_anx*nz)

!
!-----------------------------------------------------------------------
!      We need to know which processor "owns" which obs, so they can be
!      consulted on an "as needed" basis.
!-----------------------------------------------------------------------
!

      ALLOCATE(item1(nobsng),STAT=istatus)
      CALL check_alloc_status(istatus, "adas:item1:nobsng")
      ALLOCATE(ksng(nprocs),STAT=istatus)
      CALL check_alloc_status(istatus, "adas:ksng:nprocs")

      CALL mpiprocess(nobsng,indexsng,nprocs,ksng,ksngmax,            &
          isrcsng,item1,nx,ny,xsng,ysng,xs,ys)

      DEALLOCATE (item1)

!
!-----------------------------------------------------------------------
!     Mark obs that we don't "own" so we don't do unnecessary
!     computations.
!-----------------------------------------------------------------------
!

      ALLOCATE(item1(0:nprocs-1),STAT=istatus)
      CALL check_alloc_status(istatus, "adas:item1:nprocs")

      item1 = 0

      DO k=1,nmap
        IF (mpi_map(k,1) .NE. -1 ) item1(mpi_map(k,1)) = 1
      END DO
      item1(myproc) = 1

      DO k=1,nobsng
        IF (indexsng(k) == -1) CYCLE
        IF (isrcsng(k) == -1) CYCLE
        IF (item1(indexsng(k)) == 0) isrcsng(k) = 0
      END DO

      DEALLOCATE (item1)
!
!-----------------------------------------------------------------------
!
!  Although we're similar to PREPSFCGLOBS, and need to do one final task
!  (compute heights), we now use the local grid variables, not the
!  global.
!
!-----------------------------------------------------------------------
!
      CALL prepsglmdcrs_sm(mx_sng,ntime,latsng,lonsng,                 &
          xsng,ysng,hgtsng,csrcsng,                                    &
          nx,ny,nz,nvar_anx,anx,xs,ys,zp,                              &
          tem1,tem2,tem3,tem4,tem5,tem6,                               &
          rmiss,nobsng,indexsng,istatus)

    END IF
!
! Collect and distribute the data.
!

    IF (mp_opt > 0 .AND. nobsng > 0) THEN
      ALLOCATE(tems1dr(ksngmax),STAT=istat)
      CALL check_alloc_status(istat, "mpi_1dr_collect:tmps")
      ALLOCATE(temr1dr(ksngmax),STAT=istat)
      CALL check_alloc_status(istat, "mpi_1dr_collect:tmpr")

      CALL mpi_1dr_collect(hgtsng,nobsng,indexsng,                       &
        nprocs, ksng, ksngmax, mpi_map, nmap, tems1dr, temr1dr)
    END IF
    
  END IF

!
!-----------------------------------------------------------------------
!
!  Calculate initial obs differences for single-level data
!
!-----------------------------------------------------------------------
!

  IF (myproc == 0 ) PRINT *, 'Calling grdtosng'
  CALL grdtosng(nx,ny,nxlg,nylg,nz,nz_tab,mx_sng,nvar_anx,nobsng,       &
                    xs,ys,xslg,yslg,zp,icatg,anx,qback,hqback,nlvqback, &
                    tem1,tem2,tem3,tem4,tem5,tem6,                      &
                    stnsng,isrcsng,icatsng,hgtsng,xsng,ysng,            &
                    obsng,qobsng,qualsng,                               &
                    odifsng,oanxsng,thesng,trnsng,indexsng)

!
!-----------------------------------------------------------------------
!      Some data needs to be collected and distributed.
!-----------------------------------------------------------------------
!

  IF ( mp_opt > 0 .AND. nobsng > 0 ) THEN
    ALLOCATE(tems2dr(nvar_anx,ksngmax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmps")
    ALLOCATE(temr2dr(nvar_anx,ksngmax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmpr")

!
!  1D real temporary arrays already allocated, but 1D ints aren't.
!

    ALLOCATE(tems1di(ksngmax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_1di_collect:tmps")
    ALLOCATE(temr1di(ksngmax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_1di_collect:tmpr")

    CALL mpi_2dr_collect( qobsng, nvar_anx, mx_sng, nobsng, indexsng,  &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems2dr, temr2dr)
    CALL mpi_2dr_collect( odifsng, nvar_anx, mx_sng, nobsng, indexsng,  &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems2dr, temr2dr)
    CALL mpi_2dr_collect( oanxsng, nvar_anx, mx_sng, nobsng, indexsng,  &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems2dr, temr2dr)

    CALL mpi_1di_collect( icatsng, nobsng, indexsng,                    &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems1di, temr1di)

    CALL mpi_1dr_collect( thesng, nobsng, indexsng,                     &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems1dr, temr1dr)
    CALL mpi_1dr_collect( trnsng, nobsng, indexsng,                     &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems1dr, temr1dr)

!
!   2D space can't be deallocated, as the arrays get passed to "anxiter".
!

    DEALLOCATE(tems1di)
    DEALLOCATE(temr1di)
    DEALLOCATE(tems1dr)
    DEALLOCATE(temr1dr)
  END IF

!
!-----------------------------------------------------------------------
!
!  Read upper-air data, QC and convert units
!
!-----------------------------------------------------------------------
!
  IF (myproc == 0) THEN
    PRINT *, 'Calling prepuaobs'
    CALL prepuaobs(nx,ny,nz,nvar_anx,                                  &
                   nz_ua,mx_ua,nz_tab,nsrc_ua,mx_ua_file,              &
                   anx,xs,ys,zp,tem1,tem2,tem3,tem4,tem5,tem6,tem7,    &
                   nuafil,uafname,srcua,                               &
                   stnua,elevua,xua,yua,hgtua,obsua,                   &
                   qsrcua,huaqsrc,nlvuatab,                            &
                   qobsua,qualua,isrcua,nlevsua,                       &
                   rmiss,nobsua,istatus)
  END IF

!
!-----------------------------------------------------------------------
!
!  MPI issues.  Broadcast the number of data points, then the data.  If
!  there are no data values, we don't waste anyone's time.
!
!-----------------------------------------------------------------------
!

  IF (mp_opt > 0) THEN
    CALL mpupdatei(nobsua,1)
    IF (nobsua > 0) THEN
      CALL mpupdatec(stnua,mx_ua*5)
      CALL mpupdater(elevua,mx_ua)
      CALL mpupdater(xua,mx_ua)
      CALL mpupdater(yua,mx_ua)
      CALL mpupdater(hgtua,nz_ua*mx_ua)
      CALL mpupdater(obsua,nvar_anx*nz_ua*mx_ua)
      CALL mpupdater(qobsua,nvar_anx*nz_ua*mx_ua)
      CALL mpupdatei(nlvuatab,nsrc_ua)
      CALL mpupdatei(qualua,nvar_anx*nz_ua*mx_ua)
      CALL mpupdatei(isrcua,mx_ua)
      CALL mpupdatei(nlevsua,mx_ua)

!
!-----------------------------------------------------------------------
!      We need to know which processor "owns" which obs, so they can be
!      consulted on an "as needed" basis.
!-----------------------------------------------------------------------
!

       ALLOCATE(item1(nobsua),STAT=istatus)
       CALL check_alloc_status(istatus, "adas:item1:nobsua")
       ALLOCATE(kua(nprocs),STAT=istatus)
       CALL check_alloc_status(istatus, "adas:kua:nprocs")

       CALL mpiprocess(nobsua,indexua,nprocs,kua,kuamax,               &
          isrcua,item1,nx,ny,xua,yua,xs,ys)

       DEALLOCATE (item1)

!
!-----------------------------------------------------------------------
!      Mark obs that we don't "own" so we don't do unnecessary
!      computations.
!-----------------------------------------------------------------------
!

       ALLOCATE(item1(0:nprocs-1),STAT=istatus)
       CALL check_alloc_status(istatus, "adas:item1:nprocs")

       item1 = 0

       DO k=1,nmap
         IF (mpi_map(k,1) .NE. -1 ) item1(mpi_map(k,1)) = 1
       END DO
       item1(myproc) = 1

!
!-----------------------------------------------------------------------
!      Multi-level obs are never combined, so we don't have to worry.
!-----------------------------------------------------------------------
!
       DO k=1,nobsua
         IF (indexua(k) == -1) CYCLE
         IF (item1(indexua(k)) == 0) isrcua(k) = 0
       END DO

       DEALLOCATE (item1)

    END IF
  END IF

!
!-----------------------------------------------------------------------
!
!  Calculate initial obs differences for upper-air data
!
!-----------------------------------------------------------------------
!
  IF (myproc == 0) PRINT *, 'Calling grdtoua'

  CALL grdtoua(nx,ny,nxlg,nylg,nz,nz_tab,nz_ua,mx_ua,nvar_anx,nobsua,   &
              xs,ys,xslg,yslg,zp,anx,qback,hqback,nlvqback,             &
              tem1,tem2,tem3,tem4,tem5,tem6,                            &
              stnua,isrcua,elevua,xua,yua,hgtua,                        &
              obsua,qobsua,qualua,nlevsua,                              &
              odifua,oanxua,theua,trnua,indexua)

!
!-----------------------------------------------------------------------
!      Some data needs to be collected and distributed.
!-----------------------------------------------------------------------
!

  IF ( mp_opt > 0 .AND. nobsua > 0 ) THEN
    ALLOCATE(tems3dr(nvar_anx,nz_ua,kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmps")
    ALLOCATE(temr3dr(nvar_anx,nz_ua,kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmpr")

    ALLOCATE(tems1dr(kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_1dr_collect:tmps")
    ALLOCATE(temr1dr(kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_1dr_collect:tmpr")

    ALLOCATE(tems2drua(nz_ua,kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmpsua")
    ALLOCATE(temr2drua(nz_ua,kuamax),STAT=istat)
    CALL check_alloc_status(istat, "mpi_2dr_collect:tmprua")

    CALL mpi_3dr_collect( qobsua,  nvar_anx, nz_ua, mx_ua, nobsua, indexua, &
      nprocs, kua, kuamax, mpi_map, nmap, tems3dr, temr3dr)
    CALL mpi_3dr_collect( qualua,  nvar_anx, nz_ua, mx_ua, nobsua, indexua, &
      nprocs, kua, kuamax, mpi_map, nmap, tems3dr, temr3dr)
    CALL mpi_3dr_collect( odifua,  nvar_anx, nz_ua, mx_ua, nobsua, indexua, &
      nprocs, kua, kuamax, mpi_map, nmap, tems3dr, temr3dr)
    CALL mpi_3dr_collect( oanxua,  nvar_anx, nz_ua, mx_ua, nobsua, indexua, &
      nprocs, kua, kuamax, mpi_map, nmap, tems3dr, temr3dr)
    CALL mpi_1dr_collect( trnua, nobsua, indexua,                           &
       nprocs, kua, kuamax, mpi_map, nmap, tems1dr, temr1dr)
    CALL mpi_2dr_collect( theua, nz_ua, mx_ua, nobsua, indexua,  &
      nprocs, kua, kuamax, mpi_map, nmap, tems2drua, temr2drua)

    DEALLOCATE(tems1dr)
    DEALLOCATE(temr1dr)
    DEALLOCATE(tems2drua)
    DEALLOCATE(temr2drua)
  END IF

!
!-----------------------------------------------------------------------
!
!  Read radar data, unfold and convert units
!
!-----------------------------------------------------------------------
!
  IF (myproc == 0) PRINT *, 'Calling prepradar'
  CALL prepradar(nx,ny,nz,nz_tab,nvar_anx,nvar_radin,                   &
             nvar_rad,mx_rad,nsrc_rad,nz_rdr,mx_colrad,mx_pass,         &
             raduvobs,radrhobs,radistride,radkstride,                   &
             iuserad,npass,refrh,rhradobs,                              &
             xs,ys,zs,hterain,anx,qback,hqback,nlvqback,                &
             nradfil,radfname,srcrad,isrcrad,qsrcrad,qcthrrad,          &
             stnrad,latrad,lonrad,elvrad,                               &
             latradc,lonradc,xradc,yradc,irad,nlevrad,                  &
             distrad,uazmrad,vazmrad,hgtradc,theradc,trnradc,           &
             obsrad,oanxrad,odifrad,qobsrad,qualrad,                    &
             ncolrad,istatus,tem1,tem2,tem3,tem4,tem5,tem6)

!
!-----------------------------------------------------------------------
!
!  Read retrieval data.
!
!  Retrieval code has *NOT* been tested, so it may not be MPI ready!
!
!-----------------------------------------------------------------------
!
  IF (myproc == 0) PRINT *, 'Calling prepretr'
  CALL prepretr(nx,ny,nz,nvar_anx,                                      &
                nz_ret,mx_ret,mx_colret,nz_tab,nsrc_ret,                &
                nretfil,retfname,                                       &
                isrcret,srcret,nlvrttab,qsrcret,hrtqsrc,                &
                stnret,latret,lonret,elvret,                            &
                latretc,lonretc,xretc,yretc,iret,nlevret,               &
                hgtretc,obsret,qrret,qobsret,qualret,                   &
                rmiss,ncolret,tem1,istatus)

!
!-----------------------------------------------------------------------
!
!  Now get the retrieval data so that each processor only
!  contains the data it needs for its local domain plus the radius of
!  influence, where applicable.
!
!  Not guaranteed MPI ready.
!
!-----------------------------------------------------------------------
!

  IF (myproc == 0) PRINT *, 'Calling grdtoret'
  CALL grdtoret(nx,ny,nz,nz_tab,                                        &
                nz_ret,mx_ret,mx_colret,nvar_anx,ncolret,               &
                xs,ys,zp,anx,qback,hqback,nlvqback,                     &
                tem1,tem2,tem3,tem4,tem5,tem6,                          &
                stnret,iret,xretc,yretc,hgtretc,                        &
                obsret,qobsret,qualret,nlevret,                         &
                odifret,oanxret,theretc,trnretc)
!
!-----------------------------------------------------------------------
!
!  Quality-control observation differences
!
!-----------------------------------------------------------------------
!

  IF (myproc == 0) PRINT *, 'Calling qcdiff'
  CALL qcdiff(nvar_anx,nvar_rad,nvar_radin,mx_sng,nsrc_sng,             &
              indexsng,indexua,                                         &
              nz_ua,mx_ua,nsrc_ua,                                      &
              nz_rdr,mx_rad,mx_colrad,nsrc_rad,                         &
              nz_ret,mx_ret,mx_colret,nsrc_ret,                         &
              nobsng,nobsua,ncolrad,ncolret,var_anx,                    &
              stnsng,isrcsng,hgtsng,obsng,oanxsng,odifsng,              &
              qcthrsng,qualsng,                                         &
              stnua,isrcua,hgtua,obsua,oanxua,odifua,                   &
              qcthrua,qualua,nlevsua,                                   &
              stnrad,irad,isrcrad,hgtradc,obsrad,odifrad,               &
              qcthrrad,qualrad,nlevrad,                                 &
              stnret,iret,isrcret,hgtretc,                              &
              obsret,oanxret,odifret,                                   &
              qcthrret,qualret,nlevret,                                 &
              wgtsum,zsum)

  IF ( mp_opt > 0 .AND. nobsng > 0) THEN
    CALL mpi_2dr_collect( qualsng, nvar_anx, mx_sng, nobsng, indexsng,  &
      nprocs, ksng, ksngmax, mpi_map, nmap, tems2dr, temr2dr)
  END IF
  IF ( mp_opt > 0 .AND. nobsua > 0 ) THEN
    CALL mpi_3dr_collect( qualua,  nvar_anx, nz_ua, mx_ua, nobsua, indexua, &
      nprocs, kua, kuamax, mpi_map, nmap, tems3dr, temr3dr)
  END IF
!
!-----------------------------------------------------------------------
!
!  Analyze data
!
!-----------------------------------------------------------------------
!

  IF (myproc == 0) THEN
     CALL FLUSH (6)
     PRINT *, 'Calling anxiter'
  END IF

!
! Notice that we are passing "nxlg/nylg" instead of "nx/ny".
!

  CALL anxiter(nx,ny,nz,                                                &
          nvar_anx,nvar_radin,nvar_rad,nz_ua,nz_rdr,nz_ret,             &
          mx_sng,mx_ua,mx_rad,mx_colrad,mx_ret,mx_colret,               &
          nsrc_sng,nsrc_ua,nsrc_rad,nsrc_ret,ncat,                      &
          mx_pass,npass,iwstat,xs,ys,zs,icatg,xcor,var_anx,             &
          mpi_map,nmap,                                                 &
          xsng,ysng,hgtsng,thesng,trnsng,                               &
          obsng,odifsng,qobsng,qualsng,isrcsng,icatsng,nobsng,          &
          indexsng,nprocs,ksng,ksngmax,                                 &
          indexua,kua,kuamax,                                           &
          xua,yua,hgtua,theua,trnua,                                    &
          obsua,odifua,qobsua,qualua,isrcua,nlevsua,nobsua,             &
          elvrad,xradc,yradc,                                           &
          distrad,uazmrad,vazmrad,hgtradc,theradc,trnradc,              &
          obsrad,odifrad,qobsrad,qualrad,                               &
          irad,isrcrad,nlevrad,ncolrad,                                 &
          xretc,yretc,hgtretc,theretc,trnretc,                          &
          obsret,odifret,qobsret,qualret,                               &
          iret,isrcret,nlevret,ncolret,                                 &
          srcsng,srcua,srcrad,srcret,                                   &
          ianxtyp,iusesng,iuseua,iuserad,iuseret,                       &
          xyrange,kpvrsq,wlim,zrange,zwlim,                             &
          thrng,trnropt,trnrcst,trnrng,rngsqi,knt,wgtsum,zsum,          &
          corsng,corua,corrad,corret,                                   &
          oanxsng,oanxua,oanxrad,oanxret,                               &
          anx,tem1,tem2,tem3,ibegin,iend,                               &
          tems2dr,temr2dr,tems3dr,temr3dr,                              &
          istatus)
!
!-----------------------------------------------------------------------
!
!	Write to ARPSControl status file
!
!-----------------------------------------------------------------------
! Only u (index 1) is checked. Eventually should check all
! Only 1 level of UA data is checked.
!
! 10   Good
! 100  Good
! 200  Good - superob
! -9   Outside domain
! -99  Initializing value
! -199 Rejected in quality test
!
!  > 0    : used++ : in file, in domain, good point
!  = -199 : rej++  : in file, in domain, bad point
!  = -9   :        : in file, outside domain
!  = 0    :        : not in file
!
! Good data has isrc* > 0 and qual* > 0.

! single-point: SA (sao), MESO (okmeso)

  IF (myproc == 0) THEN
    WRITE (status_file, '(2A)') runname(1:lfnkey),'.adasstat'
    PRINT *, 'Creating ', TRIM(status_file)
    OPEN (UNIT=9, FILE=status_file)
  END IF

!
! MPI is slightly more complicated.  Values for stations not owned by the
! processor may say valid when then aren't.
!

  n_used_sng = 0
  DO jsta=1,nobsng
    IF (mp_opt > 0) THEN
      IF (indexsng(jsta) .NE. myproc ) qualsng(1,jsta) = -9
    END IF
    IF (isrcsng(jsta) .GT. 0 .AND. qualsng(1,jsta) .GT. 0) THEN
      n_used_sng(isrcsng(jsta)) = n_used_sng(isrcsng(jsta)) + 1
    END IF
  END DO
!
! Combine all mesonet and sao types into a single counter for 
! each group.  KB 5/14/03
!
  nmeso=0
  nsao=0
  DO jsrc=1,nsrc_sng
    IF (mp_opt > 0) THEN
      CALL mpsumi(n_used_sng(jsrc),1)
    END IF
    IF (srcsng(jsrc)(:2) .EQ. 'SA') THEN
      nsao = nsao + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:4) .EQ. 'ASOS') THEN
      nsao = nsao + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:4) .EQ. 'AWOS') THEN
      nsao = nsao + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:5) .EQ. 'SYNOP') THEN
      nsao = nsao + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:4) .EQ. 'MESO') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:5) .EQ. 'WTXMN') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:5) .EQ. 'ARMMN') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:7) .EQ. 'COAGMET') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:7) .EQ. 'HPLAINS') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    ELSE IF (srcsng(jsrc)(:4) .EQ. 'ISWS') THEN
      nmeso = nmeso + n_used_sng(jsrc)
    END IF
  END DO

  IF (myproc == 0) THEN
    WRITE (9,9901) '$sao_n_used = ', nsao
    WRITE (9,9901) '$meso_n_used = ', nmeso
  END IF

  DO jsrc=1,nsrc_sng
    IF (srcsng(jsrc)(:5) .EQ. 'MDCRS') THEN
      IF (myproc == 0) THEN
        WRITE (9,9901) '$mdcrs_n_used = ', n_used_sng(jsrc)
      END IF
    ELSE IF (srcsng(jsrc)(:4) .EQ. 'BUOY') THEN
      IF (myproc == 0) THEN
        WRITE (9,9901) '$buoy_n_used = ', n_used_sng(jsrc)
      END IF
    ELSE IF (srcsng(jsrc)(:4) .NE. 'NULL') THEN
      IF (myproc == 0) THEN
        WRITE (9,'(3A)') '# Unable to process srcsng: ', &
!            srcsng(jsrc), stnsng(jsta,1)
             srcsng(jsrc)
      END IF
    END IF
  END DO

! upper-air: NWS RAOB (raob), WPDN PRO (pro)

  n_used_ua = 0
  DO jsta=1,nobsua
    IF ((isrcua(jsta) <= 0) .or. (isrcua(jsta) > nsrc_ua)) THEN
      IF (myproc == 0) THEN
        WRITE (9,*) '# Unable to process: irsrcua=',  &
         isrcua(jsta), ' ', TRIM(stnua(jsta))
      END IF
    ELSE IF (srcua(isrcua(jsta)) .EQ. 'NWS RAOB') THEN
      IF (myproc == 0) THEN
        WRITE (9,9902) 'raob', TRIM(stnua(jsta)), nlevsua(jsta)
      END IF
      n_used_ua(isrcua(jsta)) = n_used_ua(isrcua(jsta)) + 1
    ELSE IF (srcua(isrcua(jsta)) .EQ. 'WPDN PRO') THEN
      IF (myproc == 0) THEN
        WRITE (9,9902) 'pro', TRIM(stnua(jsta)), nlevsua(jsta)
      END IF
      n_used_ua(isrcua(jsta)) = n_used_ua(isrcua(jsta)) + 1
    ELSE IF (srcua(isrcua(jsta))(:4) .NE. 'NULL') THEN
      IF (myproc == 0) THEN
        WRITE (9,'(3A)') '# Unable to process: ',  &
           srcua(isrcua(jsta)), TRIM(stnua(jsta))
      END IF
    ENDIF
  END DO

!deprecated:
!  DO jsta=1,nobsua
!! criterion: 3 good u obs out of the first 5 levels
!    IF (isrcua(jsta) .GT. 0) THEN
!      ngoodlev = 0
!
!      DO klev=1,5	!nlevsua(jsta)
!	IF (qualua(1,klev,jsta) .GT. 0) ngoodlev = ngoodlev + 1
!      END DO
!
!      IF (ngoodlev .GE. 3) THEN
!	IF (srcua(isrcua(jsta)) .EQ. 'NWS RAOB') THEN
!	  WRITE (9,9902) 'raob', TRIM(stnua(jsta)), nlevsua(jsta)
!	ELSE IF (srcua(isrcua(jsta)) .EQ. 'WPDN PRO') THEN
!	  WRITE (9,9902) 'pro', TRIM(stnua(jsta)), nlevsua(jsta)
!	ELSE IF (srcua(jsrc)(:4) .NE. 'NULL') THEN
!	  WRITE (9,'(3A)') '# Unable to process: ', &
!	                     srcua(jsrc), TRIM(stnua(jsta))
!	END IF
!	n_used_ua(isrcua(jsta)) = n_used_ua(isrcua(jsta)) + 1
!      END IF
!
!    END IF ! good isrcua
!  END DO

  DO jsrc=1,nsrc_ua
    IF (srcua(jsrc)(:8) .EQ. 'NWS RAOB') THEN
      IF (myproc == 0) THEN
        WRITE (9,9901) '$raob_n_used = ', n_used_ua(jsrc)
      ENDIF
    ELSE IF (srcua(jsrc)(:8) .EQ. 'WPDN PRO') THEN
      IF (myproc == 0) THEN
        WRITE (9,9901) '$pro_n_used  = ', n_used_ua(jsrc)
      ENDIF
    END IF
  END DO

  9902 FORMAT ('${', A, '}{stn_levels}{"', A, '"} = ', I6, ';')
  9901 FORMAT (A,I6,';')
  CALL FLUSH (6)
  CLOSE (9)

!-----------------------------------------------------------------------
!
!  Use reflectivity to establish cloud water
!
!-----------------------------------------------------------------------
!
  IF( radcldopt > 0 ) CALL radmcro(nx,ny,nz,                            &
                 mx_rad,nsrc_rad,nvar_radin,nz_rdr,mx_colrad,mx_pass,   &
                 radistride,radkstride,iuserad,npass,                   &
                 nradfil,radfname,srcrad,isrcrad,stnrad,                &
                 latrad,lonrad,elvrad,latradc,lonradc,irad,             &
                 nlevrad,xradc,yradc,hgtradc,obsrad,ncolrad,            &
                 radqvopt,radqcopt,radqropt,radptopt,                   &
                 refsat,rhrad,                                          &
                 refcld,cldrad,ceilopt,ceilmin,dzfill,                  &
                 refrain,radsetrat,radreflim,radptgain,                 &
                 xs,ys,zs,zp,j3,                                        &
                 anx(1,1,1,3),anx(1,1,1,4),anx(1,1,1,5),                &
                 ptbar,qvbar,rhostr,                                    &
                 qc,qr,qi,qs,qh,                                        &
                 tem1,tem2,tem3,tem4,tem5,tem6,tem7)
!
!-----------------------------------------------------------------------
!
!  Transfer analysed fields to ARPS variables for writing.
!
!-----------------------------------------------------------------------
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
        pprt(i,j,k)=anx(i,j,k,3)-pbar(i,j,k)
        ptprt(i,j,k)=anx(i,j,k,4)-ptbar(i,j,k)
        tgrid =anx(i,j,k,4) * (anx(i,j,k,3)/p0) ** rddcp
        qvsat=f_qvsat( anx(i,j,k,3),tgrid)
        qvmin=rhmin*qvsat
        qv(i,j,k)=MAX(qvmin,MIN(anx(i,j,k,5),qvsat))
      END DO
    END DO
  END DO

  IF (mp_opt > 0) THEN
    CALL mpsendrecv2dew(pprt,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(pprt,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(ptprt,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(ptprt,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qv,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qv,nx,ny,nz,nbc,sbc,0,tem1)
  END IF

  IF(spradopt == 1) THEN

!-----------------------------------------------------------------------
!
!  Check for superadiabatic layers in each column.
!  For spradopt=1,
!  Where superadiabatic levels are found, make the next level down
!  cooler, applying the minimum potential temperature lapse rate,
!  ptlapse.
!
!-----------------------------------------------------------------------
!
    DO j=1,ny-1
      DO i=1,nx-1
        ptprt(i,j,nz-1)=anx(i,j,nz-1,4)-ptbar(i,j,nz-1)
        DO k=nz-2,2,-1
          anx(i,j,k,4)=MIN(anx(i,j,k,4),                                &
                (anx(i,j,k+1,4)-ptlapse*(zs(i,j,k+1)-zs(i,j,k))))
          ptprt(i,j,k)=anx(i,j,k,4)-ptbar(i,j,k)
        END DO
      END DO
    END DO

  ELSE IF(spradopt == 2) THEN
!
!-----------------------------------------------------------------------
!
!  For spradopt=2,
!  Where superadiabatic levels are found, make the next level up
!  warmer, applying the minimum potential temperature lapse rate,
!  ptlapse.
!
!-----------------------------------------------------------------------
!
    DO j=1,ny-1
      DO i=1,nx-1
        ptprt(i,j,2)=anx(i,j,2,4)-ptbar(i,j,2)
        DO k=3,nz-1
          anx(i,j,k,4)=MAX(anx(i,j,k,4),                                &
                (anx(i,j,k-1,4)+ptlapse*(zs(i,j,k)-zs(i,j,k-1))))
          ptprt(i,j,k)=anx(i,j,k,4)-ptbar(i,j,k)
        END DO
      END DO
    END DO

  END IF
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=2,nx-1
        u(i,j,k)=0.5*(anx(i,j,k,1)+anx(i-1,j,k,1))
      END DO
    END DO
  END DO

  DO k=1,nz-1
    DO j=1,ny-1
      u(1,j,k)=u(2,j,k)
      u(nx,j,k)=u(nx-1,j,k)
    END DO
  END DO
!
  DO k=1,nz-1
    DO j=2,ny-1
      DO i=1,nx-1
        v(i,j,k)=0.5*(anx(i,j,k,2)+anx(i,j-1,k,2))
      END DO
    END DO
  END DO

  DO k=1,nz-1
    DO i=1,nx-1
      v(i,1,k)=v(i,2,k)
      v(i,ny,k)=v(i,ny-1,k)
    END DO
  END DO
!
!-----------------------------------------------------------------------
!
!  Adjust wind fields to minimize 3-d divergence
!  This is the first run-through for "w" in order to obtain
!  a good estimate of w for the cloud analysis.  Note here wndadj
!  is set to "2" for integration of 2-d divergence for "w" and
!  the cloud_w opt is set to 0.
!
!-----------------------------------------------------------------------
!
  CALL adjuvw( nx,ny,nz,u,v,w,                                          &
               wcont,ptprt,ptbar,                                       &
               zp,j1,j2,j3,aj3z,mapfct,rhostr,w_cld,                    &
               2,obropt,obrzero,0,                                      &
               tem1,tem2,tem3,tem4,tem5,tem6,tem7,tem8)
!
!-----------------------------------------------------------------------
!
!  Enforce vertical w boundary conditions
!
!-----------------------------------------------------------------------
!
  CALL rhouvw(nx,ny,nz,rhostr,tem1,tem2,tem3)
  CALL vbcw(nx,ny,nz,w,wcont,tbc,bbc,u,v,                               &
              rhostr,tem1,tem2,tem3,                                    &
              j1,j2,j3)
!
!-----------------------------------------------------------------------
!
!  Free-up some memory.
!
!-----------------------------------------------------------------------
!
  DEALLOCATE(anx)
!
!-----------------------------------------------------------------------
!
!  Call cloud analysis.
!
!-----------------------------------------------------------------------
!
  IF( cloudopt > 0 ) THEN
    ALLOCATE(ref_mos_3d(nx,ny,nz),STAT=istatus)
    CALL check_alloc_status(istatus, "adas:ref_mos_3d")
    ref_mos_3d=-99.

    ALLOCATE(w_cld(nx,ny,nz),STAT=istatus)
    CALL check_alloc_status(istatus, "adas:w_cld")
    w_cld=0.
    ALLOCATE(cldpcp_type_3d(nx,ny,nz),STAT=istatus)
    CALL check_alloc_status(istatus, "adas:cldpcp_type_3d")
    cldpcp_type_3d=0
    ALLOCATE(icing_index_3d(nx,ny,nz),STAT=istatus)
    CALL check_alloc_status(istatus, "adas:icing_index_3d")
    icing_index_3d=0
    ALLOCATE(l_mask_pcptype(nx,ny),STAT=istatus)
    CALL check_alloc_status(istatus, "adas:l_mask_pcptype")
    l_mask_pcptype=.false.

    CALL cmpclddrv(nx,ny,nz,i4timanx,                                   &
              xs,ys,zs,j3,hterain,latgr,longr,                          &
              nobsng,indexsng,stnsng,isrcsng,csrcsng,xsng,ysng,         &
              nxlg,nylg,xslg,yslg,                                      &
              timesng,latsng,lonsng,hgtsng,                             &
              kloud,store_amt,store_hgt,                                &
              stnrad,isrcrad,latrad,lonrad,elvrad,ixrad,jyrad,          &
              pprt,ptprt,qv,qc,qr,qi,qs,qh,w,                           &
              pbar,ptbar,qvbar,rhostr,                                  &
              ref_mos_3d,w_cld,cldpcp_type_3d,                          &
              icing_index_3d,l_mask_pcptype,                            &
              tem1,tem2,tem3,tem4,tem5,tem6,tem7,tem8,tem9,tem10,tem11)
  END IF
!
  IF(retqropt > 0 .AND. ncolret > 0) CALL retmcro(nx,ny,nz,             &
                 mx_ret,nsrc_ret,nvar_anx,nz_ret,mx_colret,             &
                 srcret,isrcret,iret,nlevret,                           &
                 xretc,yretc,hgtretc,qrret,ncolret,                     &
                 dzfill,                                                &
                 xs,ys,zs,qr)
!
!-----------------------------------------------------------------------
!
!  Create rhobar from rhostr
!
!-----------------------------------------------------------------------
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
        tem6(i,j,k)=rhostr(i,j,k)/j3(i,j,k)
      END DO
    END DO
  END DO
!
!-----------------------------------------------------------------------
!
!  Calculate and store the sound wave speed squared in csndsq.
!  Use original definition of sound speed.
!
!-----------------------------------------------------------------------
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
        csndsq(i,j,k)= cpdcv*pbar(i,j,k)/tem6(i,j,k)
      END DO
    END DO
  END DO
!
  IF(hydradj == 1 .OR. hydradj == 2) THEN
    pconst=0.5*g*dz
!
!-----------------------------------------------------------------------
!
!  Create thermal buoyancy at each scalar point,
!  which is stored in tem2
!
!-----------------------------------------------------------------------
!
    DO k=1,nz
      DO j=1,ny
        DO i=1,nx
          qvprt=qv(i,j,k)-qvbar(i,j,k)
          qtot=qc(i,j,k)+qr(i,j,k)+                                     &
               qi(i,j,k)+qs(i,j,k)+qh(i,j,k)
          tem2(i,j,k)=j3(i,j,k)*tem6(i,j,k)*                            &
                    g*( (ptprt(i,j,k)/ptbar(i,j,k)) +                   &
                        (qvprt/(rddrv+qvbar(i,j,k))) -                  &
                        ((qvprt+qtot)/(1.+qvbar(i,j,k))) )
        END DO
      END DO
    END DO
!
!-----------------------------------------------------------------------
!
!  Average thermal buoyancy to w points
!  which is stored in tem3
!
!-----------------------------------------------------------------------
!
    CALL avgsw(tem2,nx,ny,nz,1,nx,1,ny, tem3)

    IF(hydradj == 1) THEN

      DO i=1,nx
        DO j=1,ny
          tem1(i,j,1)=pprt(i,j,1)
          DO k=2,nz-2
            tem1(i,j,k)=                                                &
                  ( (1. - (pconst*j3(i,j,k-1)/csndsq(i,j,k-1)) )*       &
                      tem1(i,j,k-1) +                                   &
                      dz*tem3(i,j,k) ) /                                &
                      (1. + (pconst*j3(i,j,k)/csndsq(i,j,k)) )
            IF(j == 26 .AND. MOD(i,10) == 0) THEN
              IF(k == nz-2) PRINT *, '            Point i= ',i, '  j=26'
              PRINT *, ' k,pprt,tem1,diff =',                           &
                  k,pprt(i,j,k),tem1(i,j,k),                            &
                  (tem1(i,j,k)-pprt(i,j,k))
            END IF
            pprt(i,j,k)=tem1(i,j,k)
          END DO
          pprt(i,j,nz-1)=pprt(i,j,nz-2)
        END DO
      END DO

    ELSE IF(hydradj == 2) THEN

      DO i=1,nx
        DO j=1,ny
          tem1(i,j,nz-1)=pprt(i,j,nz-1)
          DO k=nz-2,2,-1
            tem1(i,j,k)=                                                &
                  ( (1.+ (pconst*j3(i,j,k+1)/csndsq(i,j,k+1)) )*        &
                      tem1(i,j,k+1) -                                   &
                      dz*tem3(i,j,k+1) ) /                              &
                      (1.- (pconst*j3(i,j,k  )/csndsq(i,j,k  )) )
            IF(j == 26 .AND. MOD(i,10) == 0) THEN
              IF(k == nz-2) PRINT *, '            Point i= ',i, '  j=26'
              PRINT *, ' k,pprt,tem1,diff =',                           &
                  k,pprt(i,j,k),tem1(i,j,k),                            &
                  (tem1(i,j,k)-pprt(i,j,k))
            END IF
            pprt(i,j,k)=tem1(i,j,k)
          END DO
          pprt(i,j,1)=pprt(i,j,2)
        END DO
      END DO
    END IF
  ELSE IF (hydradj == 3) THEN
!
!-----------------------------------------------------------------------
!
!  Calculate total pressure, store in tem1.
!  Calculate virtual temperature, store in tem2.
!
!-----------------------------------------------------------------------
!
    DO k=1,nz
      DO j=1,ny
        DO i=1,nx
          tem1(i,j,k) = pbar(i,j,k)+pprt(i,j,k)
          temp = (ptbar(i,j,k)+ptprt(i,j,k))*                           &
                 ((tem1(i,j,k)/p0)**rddcp)
          tem2(i,j,k) = temp*(1.0+rvdrd*qv(i,j,k))/                     &
                             (1.0+qv(i,j,k))
        END DO
      END DO
    END DO
!
!-----------------------------------------------------------------------
!
!  Integrate hydrostatic equation, begining at k=2
!
!-----------------------------------------------------------------------
!
    pconst=-g/rd
    DO k=3,nz-1
      DO j=1,ny-1
        DO i=1,nx-1
          tvbar=0.5*(tem2(i,j,k)+tem2(i,j,k-1))
          tem1(i,j,k)=tem1(i,j,k-1)*                                    &
                     EXP(pconst*(zs(i,j,k)-zs(i,j,k-1))/tvbar)
          pprt(i,j,k)=tem1(i,j,k)-pbar(i,j,k)
        END DO
      END DO
    END DO
    DO j=1,ny-1
      DO i=1,nx-1
        tvbar=tem2(i,j,2)
        tem1(i,j,1)=tem1(i,j,2)*                                        &
                   EXP(pconst*(zs(i,j,1)-zs(i,j,2))/tvbar)
        pprt(i,j,1)=tem1(i,j,1)-pbar(i,j,1)
      END DO
    END DO
  END IF
!
!-----------------------------------------------------------------------
!
!  Adjust wind fields to minimize 3-d divergence
!
!-----------------------------------------------------------------------
!
  CALL adjuvw( nx,ny,nz,u,v,w,                                          &
               wcont,ptprt,ptbar,                                       &
               zp,j1,j2,j3,aj3z,mapfct,rhostr,w_cld,                    &
               wndadj,obropt,obrzero,cldwopt,                           &
               tem1,tem2,tem3,tem4,tem5,tem6,tem7,tem8)
!
!-----------------------------------------------------------------------
!
!  Enforce vertical w boundary conditions
!
!-----------------------------------------------------------------------
!
  CALL rhouvw(nx,ny,nz,rhostr,tem1,tem2,tem3)
  CALL vbcw(nx,ny,nz,w,wcont,tbc,bbc,u,v,                               &
              rhostr,tem1,tem2,tem3,                                    &
              j1,j2,j3)
!
!-----------------------------------------------------------------------
!
!  Enforce boundary conditions
!  Use zero gradient for lateral bc, and rigid for top,bottom.
!
!-----------------------------------------------------------------------
!
  ebc = 3
  wbc = 3
  nbc = 3
  sbc = 3
  tbc = 1
  bbc = 1
!
  DO k=1,nz
    DO j=1,ny
      pdteb(j,k)=0.
      pdtwb(j,k)=0.
    END DO
    DO i=1,nx
      pdtnb(i,k)=0.
      pdtsb(i,k)=0.
    END DO
  END DO
!
  CALL bcu(nx,ny,nz,0., u,                                              &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value. Use local value instead,
                             ! since ADAS is still not parallized.

  CALL bcv(nx,ny,nz,0., v,                                              &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL lbcw(nx,ny,nz,0.0,w,wcont,                                       &
            pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,                    &
            ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0.,ptprt,ptprt,ptprt,                            &
              pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,          &
              ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qv,qv,qv,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qc,qc,qc,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qr,qr,qr,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qi,qi,qi,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qs,qs,qs,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

  CALL bcsclr(nx,ny,nz,0., qh,qh,qh,                                    &
           pdteb,pdtwb,pdtnb,pdtsb,ebc,wbc,nbc,sbc,tbc,bbc,             &
           ebc,wbc,nbc,sbc)  ! should be global value.

!
!-----------------------------------------------------------------------
!
!  Apply extrapolated gradient bc to pressure for geostrophic
!  type balance to winds along lateral boundaries.  Consistent
!  with horizontal winds constant.
!
!-----------------------------------------------------------------------
!
  DO k=2,nz-2
    DO j=1,ny-1
      pprt(1,j,k)=2.*pprt(2,j,k)-pprt(3,j,k)
    END DO
  END DO

  DO k=2,nz-2
    DO j=1,ny-1
      pprt(nx-1,j,k)=2.*pprt(nx-2,j,k)-pprt(nx-3,j,k)
    END DO
  END DO

  DO k=2,nz-2
    DO i=1,nx-1
      pprt(i,ny-1,k)=2.*pprt(i,ny-2,k)-pprt(i,ny-3,k)
    END DO
  END DO

  DO k=2,nz-2
    DO i=1,nx-1
      pprt(i,1,k)=2.*pprt(i,2,k)-pprt(i,3,k)
    END DO
  END DO

!
!-----------------------------------------------------------------------
!
!  For top and bottom bc, apply hydrostatic pressure equation to
!  total pressure, then subtract pbar.
!
!-----------------------------------------------------------------------
!
  pconst=-g/rd
  DO j=1,ny-1
    DO i=1,nx-1
      pr2 = pbar(i,j,2)+pprt(i,j,2)
      temp = (ptbar(i,j,2)+ptprt(i,j,2))*                               &
             ((pr2/p0)**rddcp)
      tvbar = temp*(1.0+rvdrd*qv(i,j,2))/                               &
                         (1.0+qv(i,j,2))
      pr1=pr2*EXP(pconst*(zs(i,j,1)-zs(i,j,2))/tvbar)
      pprt(i,j,1)=pr1-pbar(i,j,1)

      pr2 = pbar(i,j,nz-2)+pprt(i,j,nz-2)
      temp = (ptbar(i,j,nz-2)+ptprt(i,j,nz-2))*                         &
             ((pr2/p0)**rddcp)
      tvbar= temp*(1.0+rvdrd*qv(i,j,nz-2))/                             &
                         (1.0+qv(i,j,nz-2))
      pr1=pr2*EXP(pconst*(zs(i,j,nz-1)-zs(i,j,nz-2))/tvbar)
      pprt(i,j,nz-1)=pr1-pbar(i,j,nz-1)
    END DO
  END DO
!
!-----------------------------------------------------------------------
!
!  Adjust surface (skin) temperature based on radiation and
!  current air temperature.
!
!-----------------------------------------------------------------------
!
  IF(tsfcopt > 0 ) THEN

    IF (radopt == 2) THEN
      rbufsz = n2d_radiat*nx*ny + n3d_radiat*nx*ny*nz
    ELSE
      rbufsz = 1
    END IF

    ALLOCATE(rsirbm(nx,ny))
    rsirbm = 0.
    ALLOCATE(rsirdf(nx,ny))
    rsirdf = 0.
    ALLOCATE(rsuvbm(nx,ny))
    rsuvbm = 0.
    ALLOCATE(rsuvdf(nx,ny))
    rsuvdf = 0.

    ALLOCATE(cosz(nx,ny))
    cosz = 0.
    ALLOCATE(cosss(nx,ny))
    cosss = 0.


    ALLOCATE(fdirir(nx,ny))
    fdirir = 0.
    ALLOCATE(fdifir(nx,ny))
    fdifir = 0.
    ALLOCATE(fdirpar(nx,ny))
    fdirpar= 0.
    ALLOCATE(fdifpar(nx,ny))
    fdifpar= 0.

    ALLOCATE(temrad1(nx,ny,nz))
    temrad1 = 0.
    ALLOCATE(tem12(nx,ny,nz))
    tem12 = 0.
    ALLOCATE(tem13(nx,ny,nz))
    tem13 = 0.
    ALLOCATE(tem14(nx,ny,nz))
    tem14 = 0.
    ALLOCATE(tem15(nx,ny,nz))
    tem15 = 0.
    ALLOCATE(tem16(nx,ny,nz))
    tem16 = 0.
    ALLOCATE(tem17(nx,ny,nz))
    tem17 = 0
    ALLOCATE(radbuf(rbufsz))
    radbuf = 0.
    ALLOCATE(sh(nx,ny))
    sh = 0.

    CALL adjtsfc(nx,ny,nz,rbufsz,                                       &
               ptprt,pprt,qv,qc,qr,qi,qs,qh,                            &
               ptbar,pbar,ppi,rhostr,                                   &
               x,y,z,zp,j3inv,                                          &
               soiltyp, tsoil(1,1,1,0),qsoil(1,1,1,0),snowdpth,         &
               radfrc, radsw, rnflx, radswnet, radlwin,                 &
               rsirbm,rsirdf,rsuvbm,rsuvdf,                             &
               cosz, cosss,                                             &
               fdirir,fdifir,fdirpar,fdifpar,                           &
               tem1,tem2,tem3,tem4,tem5,tem6,tem7,tem8,                 &
               tem9,temrad1,tem11,tem12,tem13,tem14,tem15,tem16,        &
               radbuf, sh, tem17)

    ! DTD: placed call to fix_soil_nstp here, to propagate adjusted soil temperatures above
    ! to the other soil types, if nstyp > 1
    ! The call to adtsfc above only adjusts the soil temperatures for one soil type

    CALL fix_soil_nstyp(nx,ny,nzsoil,1,nstyp,tsoil,  &
                          qsoil,wetcanp)


    DEALLOCATE(rsirbm)
    DEALLOCATE(rsirdf)
    DEALLOCATE(rsuvbm)
    DEALLOCATE(rsuvdf)

    DEALLOCATE(cosz)
    DEALLOCATE(cosss)

    DEALLOCATE(fdirir)
    DEALLOCATE(fdifir)
    DEALLOCATE(fdirpar)
    DEALLOCATE(fdifpar)

    DEALLOCATE(tem12)
    DEALLOCATE(tem13)
    DEALLOCATE(tem14)
    DEALLOCATE(tem15)
    DEALLOCATE(tem16)
    DEALLOCATE(radbuf)
    DEALLOCATE(sh)
    DEALLOCATE(tem17)

  END IF

!
!-----------------------------------------------------------------------
!
!  Calculate analysis increments and write to file, if desired.
!
!-----------------------------------------------------------------------
!

  IF(incrdmp > 0) THEN
    CALL incrcalc(nx,ny,nz,nxndg,nyndg,nzndg,                           &
                  u,v,w,pprt,ptprt,qv,                                  &
                  qc,qr,qi,qs,qh,                                       &
                  uincr,vincr,wincr,pincr,ptincr,qvincr,                &
                  qcincr,qrincr,qiincr,qsincr,qhincr,                   &
                  istatus)

    CALL incrdump(nxndg,nyndg,nzndg,incrdmp,incrhdfcompr,incdmpf,       &
                  uincr,vincr,wincr,pincr,ptincr,qvincr,                &
                  qcincr,qrincr,qiincr,qsincr,qhincr,                   &
                  uincdmp,vincdmp,wincdmp,                              &
                  pincdmp,ptincdmp,qvincdmp,                            &
                  qcincdmp,qrincdmp,qiincdmp,qsincdmp,qhincdmp,         &
                  istatus)

  END IF
!
!-----------------------------------------------------------------------
!
!  Data dump of the model grid and base state arrays:
!
!-----------------------------------------------------------------------
!
  IF (mp_opt > 0) THEN
    CALL mpsendrecv2dew(u,nx,ny,nz,ebc,wbc,1,tem1)
    CALL mpsendrecv2dns(u,nx,ny,nz,nbc,sbc,1,tem1)
 
    CALL mpsendrecv2dew(v,nx,ny,nz,ebc,wbc,2,tem1)
    CALL mpsendrecv2dns(v,nx,ny,nz,nbc,sbc,2,tem1)

    CALL mpsendrecv2dew(w,nx,ny,nz,ebc,wbc,3,tem1)
    CALL mpsendrecv2dns(w,nx,ny,nz,nbc,sbc,3,tem1)

    CALL mpsendrecv2dew(ptprt,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(ptprt,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(pprt,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(pprt,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qv,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qv,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qc,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qc,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qr,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qr,nx,ny,nz,nbc,sbc,0,tem1)
 
    CALL mpsendrecv2dew(qi,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qi,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qs,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qs,nx,ny,nz,nbc,sbc,0,tem1)

    CALL mpsendrecv2dew(qh,nx,ny,nz,ebc,wbc,0,tem1)
    CALL mpsendrecv2dns(qh,nx,ny,nz,nbc,sbc,0,tem1)

  END IF

  DO k=1,nz
    DO j=1,ny
      DO i=1,nx
        tem1(i,j,k)=0.
      END DO
    END DO
  END DO
!
  DO k=1,nz-1
    DO j=1,ny-1
      DO i=1,nx-1
        tem2(i,j,k)=rhostr(i,j,k)/j3(i,j,k)
      END DO
    END DO
  END DO
!
  IF( hdmpfmt == 5 ) GO TO 700
  IF( hdmpfmt == 9 ) GO TO 700
!
!-----------------------------------------------------------------------
!
!  Find a unique name basdmpfn(1:lbasdmpf) for the grid and
!  base state array dump file
!
!-----------------------------------------------------------------------
!

  CALL gtbasfn(runname(1:lfnkey),dirname,ldirnam,hdmpfmt,               &
               mgrid,nestgrd,basdmpfn,lbasdmpf)

  IF (myproc == 0) WRITE(6,'(1x,a,a)')                                  &
       'Data dump of grid and base state arrays into file ',            &
        basdmpfn(1:lbasdmpf)

  CALL setcornerll( nx,ny,x,y )   ! set the corner lat/lon

  grdbas = 1                ! Dump out grid and base state arrays only

!    blocking inserted for ordering i/o for message passing
  DO i=0,nprocs-1,max_fopen
!  DO i=0,0,max_fopen

    IF(myproc >= i.AND.myproc <= i+max_fopen-1)THEN

      CALL dtadump(nx,ny,nz,nzsoil,nstyps,                              &
               hdmpfmt,nchdmp,basdmpfn(1:lbasdmpf),                     &
               grdbas,filcmprs,                                         &
               u,v,w,ptprt,pprt,qv,                                     &
               qc,qr,qi,qs,qh,                                          &
               tem1,tem1,tem1,                                          &
               ubar,vbar,tem1,ptbar,pbar,tem2,qvbar,                    &
               x,y,z,zp,zpsoil,                                         &
               soiltyp,stypfrct,vegtyp,lai,roufns,veg,                  &
               tsoil,qsoil,wetcanp,snowdpth,                            &
               raing,rainc,prcrate,                                     &
               radfrc,radsw,rnflx,radswnet,radlwin,                     &
               usflx,vsflx,ptsflx,qvsflx,                               &
               tem3,tem4,tem5)
     END IF
     IF (mp_opt > 0) CALL mpbarrier
   END DO
   
!
!-----------------------------------------------------------------------
!
!  Find a unique name hdmpfn(1:ldmpf) for history dump data set
!  at time 'curtim'.
!
!-----------------------------------------------------------------------
!
  700 CONTINUE

  CALL gtdmpfn(runname(1:lfnkey),dirname,                               &
               ldirnam,curtim,hdmpfmt,                                  &
               mgrid,nestgrd, hdmpfn, ldmpf)

  IF (myproc == 0)                                                      &
    WRITE(6,'(1x,a,a)') 'History data dump in file ',hdmpfn(1:ldmpf)

  grdbas = 0                ! No base state or grid array is dumped.

!    blocking inserted for ordering i/o for message passing
  DO i=0,nprocs-1,max_fopen
!  DO i=0,0,max_fopen

    IF(myproc >= i.AND.myproc <= i+max_fopen-1)THEN

      CALL dtadump(nx,ny,nz,nzsoil,nstyps,                              &
               hdmpfmt,nchdmp,hdmpfn(1:ldmpf),                          &
               grdbas,filcmprs,                                         &
               u,v,w,ptprt,pprt,qv,                                     &
               qc,qr,qi,qs,qh,                                          &
               tem1,tem1,tem1,                                          &
               ubar,vbar,tem1,ptbar,pbar,tem2,qvbar,                    &
               x,y,z,zp,zpsoil,                                         &
               soiltyp,stypfrct,vegtyp,lai,roufns,veg,                  &
               tsoil,qsoil,wetcanp,snowdpth,                            &
               raing,rainc,prcrate,                                     &
               radfrc,radsw,rnflx,radswnet,radlwin,                     &
               usflx,vsflx,ptsflx,qvsflx,                               &
               tem3,tem4,tem5)
    END IF
    IF (mp_opt > 0) CALL mpbarrier
  END DO

  IF (mp_opt > 0) THEN
    IF (myproc == 0) WRITE(6,'(/,5x,a)') '==== ADAS_MPI terminated normally ===='
    CALL mpexit(0)
  ELSE
    WRITE(6,'(/,5x,a)') '==== ADAS terminated normally ===='
    STOP
  END IF
END PROGRAM arpsdas  

!

SUBROUTINE exsufx(fname,lenfnm,suffix,maxsuf,dotloc,lensuf) 4
  IMPLICIT NONE
  INTEGER :: lenfnm
  INTEGER :: maxsuf
  CHARACTER (LEN=lenfnm) :: fname
  CHARACTER (LEN=maxsuf) :: suffix
  INTEGER :: lensuf
  INTEGER :: dotloc
!
  INTEGER :: i,j
!
  dotloc=0
  lensuf=0
  DO i=1,maxsuf
    suffix(i:i)=' '
  END DO
  DO i=lenfnm,1,-1
    IF(fname(i:i) == '.') EXIT
  END DO
  dotloc=i
  IF(dotloc > 0) THEN
    lensuf=MIN(maxsuf,lenfnm-i)
    DO i=1,lensuf
      j=dotloc+i
      suffix(i:i)=fname(j:j)
    END DO
  END IF
  RETURN
END SUBROUTINE exsufx
!

SUBROUTINE exfroot(fname,lenfnm,froot,mxroot,lenroot) 3
  IMPLICIT NONE
  INTEGER :: lenfnm
  INTEGER :: mxroot
  CHARACTER (LEN=1) :: fname(lenfnm)
  CHARACTER (LEN=1) :: froot(mxroot)
  INTEGER :: lenroot

  INTEGER :: i
  INTEGER :: slashloc
  INTEGER :: dotloc

  DO i=lenfnm,1,-1
    IF(fname(i) == '/') EXIT
  END DO

  slashloc=i
  DO i=slashloc,lenfnm
    IF(fname(i) == '.') EXIT
  END DO

  dotloc=i
  lenroot=(dotloc-slashloc)-1
  DO i=1,lenroot
    froot(i)=fname(slashloc+i)
  END DO
  RETURN
END SUBROUTINE exfroot
!
!##################################################################
!##################################################################
!######                                                      ######
!######                  SUBROUTINE SETCAT                   ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!

SUBROUTINE setcat(nx,ny,nz,ccatopt,zs,                                  & 3,10
           ptprt,pprt,qv,qc,qr,qi,qs,qh,                                &
           ptbar,pbar,                                                  &
           prcrate,icatg)
!
!
!-----------------------------------------------------------------------
!
!  PURPOSE:
!
!  Assign categories to grid locations according to the background
!  state to account for decorrelation across areas with active
!  parameterized convection and those without.
!
!
!-----------------------------------------------------------------------
!
!
!  AUTHOR: Keith Brewster
!  8/7/98
!
!  MODIFICATION HISTORY:
!
!  2/2/06  Kevin Thomas
!  MPI the counts.
!
!-----------------------------------------------------------------------
!
!  INPUT :
!
!  OUTPUT:
!
!-----------------------------------------------------------------------
!
  IMPLICIT NONE

  INCLUDE 'mp.inc'

  INTEGER :: nx,ny,nz
  INTEGER :: ccatopt
  REAL :: zs    (nx,ny,nz)  ! The physical height coordinate defined at
                            ! w-point of the staggered grid.
  REAL :: ptprt (nx,ny,nz)  ! Perturbation potential temperature (K)
  REAL :: pprt  (nx,ny,nz)  ! Perturbation pressure (Pascal)
  REAL :: qv    (nx,ny,nz)  ! Water vapor specific humidity (kg/kg)
  REAL :: qc    (nx,ny,nz)  ! Cloud water mixing ratio (kg/kg)
  REAL :: qr    (nx,ny,nz)  ! Rain water mixing ratio (kg/kg)
  REAL :: qi    (nx,ny,nz)  ! Cloud ice mixing ratio (kg/kg)
  REAL :: qs    (nx,ny,nz)  ! Snow mixing ratio (kg/kg)
  REAL :: qh    (nx,ny,nz)  ! Hail mixing ratio (kg/kg)

  REAL :: ptbar (nx,ny,nz)     ! Base state potential temperature (K)
  REAL :: pbar  (nx,ny,nz)     ! Base state pressure (Pascal).
  REAL :: prcrate(nx,ny,4)     ! precipitation rate (kg/(m**2*s))
                               ! prcrate(1,1,1) = total precipitation rate
                               ! prcrate(1,1,2) = grid scale precip. rate
                               ! prcrate(1,1,3) = cumulus precip. rate
                               ! prcrate(1,1,4) = microphysics precip. rate
  INTEGER :: icatg(nx,ny)
!
  REAL :: prctrw,bltop,rhrkul,thevrkul
  PARAMETER (prctrw=1.0E-04,    & !  (kg/(m**2*s))
         bltop=1000.,   & !  m
         rhrkul=0.8,                                                    &
             thevrkul=9.0)  !  K**2
!
  INTEGER :: i,j
!  integer knt,k
  INTEGER :: nxlg,nylg
  INTEGER :: knt1,knt2a,knt2b,knt3,knt4
  INTEGER :: is_dup
  REAL :: pr,temp,qvsat,rh
!  real rhsum,rhmean
!  real the,thesum,thesq,themean,thevar
!
!-----------------------------------------------------------------------
!
!  Function f_qvsat and inline directive for Cray PVP
!
!-----------------------------------------------------------------------
!
  REAL :: f_qvsat

!fpp$ expand (f_qvsat)
!!dir$ inline always f_qvsat

!
!-----------------------------------------------------------------------
!
!  Include files
!
!-----------------------------------------------------------------------
!
!
  INCLUDE 'phycst.inc'
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!
  knt1=0
  knt2a=0
  knt2b=0
  knt3=0
  knt4=0
!
!-----------------------------------------------------------------------
!
!  Initialize with default of no precip or precip influence
!
!  We jump thru some extra hoops to make sure the MPI and non-MPI counts
!  are the same.  If we don't, overlap points can be counted twice.
!
!-----------------------------------------------------------------------
!
  DO j=1,ny-1
    DO i=1,nx-1
      icatg(i,j)=1
    END DO
  END DO
!
  IF(ccatopt == 1) THEN
    DO j=1,ny-1
      is_dup = 0
      IF ((mp_opt > 0) .AND. (j >= ny-2) .AND. (loc_y .NE. nproc_y)) is_dup=1
      DO i=1,nx-1
        IF ((mp_opt > 0) .AND. (i >= nx-2) .AND. (loc_x .NE. nproc_x)) is_dup=1
!
!-----------------------------------------------------------------------
!
!  Is convective precip turned on or heavy rain occuring?
!
!-----------------------------------------------------------------------
!
        IF (prcrate(i,j,3) > 0. .OR. prcrate(i,j,1) > prctrw) THEN
          IF (is_dup == 0) knt4=knt4+1
          icatg(i,j)=4
!      print *, ' set i,j:',i,j,' cat 4',' prcrate(1):',
!    :             prcrate(i,j,1),' prcrate(3):',prcrate(i,j,3)
!
!-----------------------------------------------------------------------
!
!  Is it currently raining?
!
!-----------------------------------------------------------------------
!
        ELSE IF ( prcrate(i,j,1) > 0. ) THEN
          IF (is_dup == 0) knt3=knt3+1
          icatg(i,j)=3
!      print *, ' set i,j:',i,j,' cat 3',' prcrate(1):',
!    :             prcrate(i,j,1),' prcrate(3):',prcrate(i,j,3)
!
!-----------------------------------------------------------------------
!
!  Evidence of rain-cooled air?
!  Lapse rate close to a moist adiabatic lapse rate in the lowest 2-km,
!  and a high relative humidity in that layer.  Or a high relative
!  humidity at the first level above ground.
!
!-----------------------------------------------------------------------
!
        ELSE
!
!-----------------------------------------------------------------------
!
!  For the layer 0-2km above first grid level (k=2).
!  Calculate the mean relative humidity.
!  Calculate the standard deviation of saturated equivalent
!  potential temperature.
!
!-----------------------------------------------------------------------
!
!      rhsum=0.
!      thesum=0.
!      thesq=0.
!      knt=0
!      DO 40 k=2,nz-1
!        IF(k.gt.2 .and. (zs(i,j,k)-zs(i,j,2)).gt.bltop) GO TO 41
!        knt=knt+1
!        pr=pprt(i,j,k)+pbar(i,j,k)
!        temp=(ptprt(i,j,k)+ptbar(i,j,k)) * (pr/p0)**rddcp
!        qvsat=f_qvsat( pr,temp )
!        rh=min(1.,(qv(i,j,k)/qvsat))
!        the=F_PT2PTE( pr,(ptprt(i,j,k)+ptbar(i,j,k)),qvsat)
!        rhsum=rhsum+rh
!        thesum=thesum+the
!        thesq=thesq+(the*the)
!  40     CONTINUE
!  41     CONTINUE
!      IF(knt.gt.0) THEN
!        rhmean=rhsum/float(knt)
!        themean=thesum/float(knt)
!      ELSE
!        rhmean=0.
!        themean=0.
!      END IF
!      IF(knt.gt.1) THEN
!        thevar=(thesq-((thesum*thesum)/float(knt)))/float(knt-1)
!      ELSE
!        thevar=9999.
!      END IF
!
!      IF (rhmean.gt.rhrkul .and. thevar.lt.thevrkul) THEN
!        knt2a=knt2a+1
!        icatg(i,j)=2
!        print *, ' set i,j:',i,j,' cat 2',' prcrate(1):',
!    :             prcrate(i,j,1),' prcrate(3):',prcrate(i,j,3)
!      ELSE
!
          pr=pprt(i,j,2)+pbar(i,j,2)
          temp=(ptprt(i,j,2)+ptbar(i,j,2)) * (pr/p0)**rddcp
          qvsat=f_qvsat( pr,temp )
          rh=qv(i,j,2)/qvsat
          IF(rh > 0.8) THEN
            IF (is_dup == 0) knt2b=knt2b+1
            icatg(i,j)=2
!          print *, ' set i,j:',i,j,' cat 2*',' RH(2) = ',rh
          END IF

!      END IF
!      IF (mod(i,20).eq.0 .and. mod(j,10).eq.0)  THEN
!        print *, i,j,' rhmean=',rhmean,
!    :               ' thevar=',thevar,' icat=',icatg(i,j)
!        print *, ' '
!      END IF

        END IF
      END DO
    END DO
    IF (mp_opt > 0 ) THEN
      CALL mpsumi(knt2a,1)
      CALL mpsumi(knt2b,1)
      CALL mpsumi(knt3,1)
      CALL mpsumi(knt4,1)
      nxlg = (nx - 3) * nproc_x + 3
      nylg = (ny - 3) * nproc_y + 3
      knt1=((nxlg-1)*(nylg-1))-knt2a-knt2b-knt3-knt4
    ELSE
      knt1=((nx-1)*(ny-1))-knt2a-knt2b-knt3-knt4
    END IF

    IF (myproc == 0 ) THEN
      WRITE(6,'(a)') ' Precip correlation category assignment counts'
      WRITE(6,'(a,i6)') '     cat  1: ',knt1
      WRITE(6,'(a,i6)') '     cat 2a: ',knt2a
      WRITE(6,'(a,i6)') '     cat 2b: ',knt2b
      WRITE(6,'(a,i6)') '     cat  3: ',knt3
      WRITE(6,'(a,i6)') '     cat  4: ',knt4
    END IF
  END IF
!
  CALL iedgfill(icatg,1,nx,1,nx-1, 1,ny,1,ny-1,1,1,1,1)
!
  RETURN
END SUBROUTINE setcat