!########################################################################
!########################################################################
!######                                                            ######
!######                    PROGRAM ARPSVERIF                       ######
!######                                                            ######
!######                      Developed by                          ######
!######         Center for Analysis and Prediction of Storms       ######
!######                   University of Oklahoma                   ######
!######                                                            ######
!########################################################################
!########################################################################


PROGRAM arpsverif,90

!-----------------------------------------------------------------------
!
! PURPOSE:
!
! Calculates verification statistics for ARPS forecasts.
!
!-----------------------------------------------------------------------
!
! HISTORY:
!   2002/04/03  First written by Jason J. Levit
!
!-----------------------------------------------------------------------
!
! Use modules
!
!-----------------------------------------------------------------------

!-----------------------------------------------------------------------
!
! Variable Declarations:
!
!-----------------------------------------------------------------------

  IMPLICIT NONE                    ! Force explicit declarations

  INCLUDE 'globcst.inc'
  INCLUDE 'phycst.inc'
  INCLUDE 'vericst.inc'
  INCLUDE 'grid.inc'

!
!-----------------------------------------------------------------------
!
!  Data arrays 
!
!-----------------------------------------------------------------------
!
  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(:,:,:) ! The physical height coordinate of soil
                                     ! model 

!
  REAL, ALLOCATABLE :: hterain (:,:)       ! Terrain height
!
  REAL, ALLOCATABLE :: uprt   (:,:,:)    ! Perturbation u-velocity (m/s)
  REAL, ALLOCATABLE :: vprt   (:,:,:)    ! Perturbation v-velocity (m/s)
  REAL, ALLOCATABLE :: wprt   (:,:,:)    ! Perturbation w-velocity (m/s)
  REAL, ALLOCATABLE :: ptprt  (:,:,:)    ! Perturbation potential temperature (K)
  REAL, ALLOCATABLE :: pprt   (:,:,:)    ! Perturbation pressure (Pascal)
  REAL, ALLOCATABLE :: qvprt  (:,:,:)    ! Perturbation 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 :: kmh    (:,:,:)    ! Horizontal turb. mixing coef. for
                                         ! momentum. ( m**2/s )
  REAL, ALLOCATABLE :: kmv    (:,:,:)    ! Vertical turb. mixing coef. for
                                         ! momentum. ( m**2/s )

  REAL, ALLOCATABLE :: ubar   (:,:,:)    ! Base state u-velocity (m/s)
  REAL, ALLOCATABLE :: vbar   (:,:,:)    ! Base state v-velocity (m/s)
  REAL, ALLOCATABLE :: wbar   (:,:,:)    ! Base state w-velocity (m/s)
  REAL, ALLOCATABLE :: ptbar  (:,:,:)    ! Base state potential temperature (K)
  REAL, ALLOCATABLE :: pbar   (:,:,:)    ! Base state pressure (Pascal)
  REAL, ALLOCATABLE :: rhobar (:,:,:)    ! Base state air density (kg/m**3)
  REAL, ALLOCATABLE :: qvbar  (:,:,:)    ! Base state water vapor specific
                                                                ! humidity (kg/kg)
  INTEGER :: nstyps

  INTEGER, ALLOCATABLE :: soiltyp (:,:,:)       ! Soil type
  REAL, ALLOCATABLE :: stypfrct(:,:,:)          ! Soil type
  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 :: wetcanp(:,:,:)       ! Canopy water amount
  REAL, ALLOCATABLE :: snowdpth(:,:)        ! Snow depth (m)

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

  REAL, ALLOCATABLE :: radfrc(:,:,:)      ! Radiation forcing (K/s)
  REAL, ALLOCATABLE :: radsw (:,:)        ! Solar radiation reaching the surface
  REAL, ALLOCATABLE :: rnflx (:,:)        ! Net radiation flux absorbed by surface
  REAL, ALLOCATABLE :: radswnet(:,:)      ! Net shortwave radiation
  REAL, ALLOCATABLE :: radlwin(:,:)       ! Incoming longwave radiation

  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)

  REAL, ALLOCATABLE :: model_data(:,:,:)
  REAL, ALLOCATABLE :: obsrv_data(:,:,:)
                         !(:,:,1) = sfc temp
                         !(:,:,2) = sfc dewpoint
                         !(:,:,3) = sfc wind dir
                         !(:,:,4) = sfc wind speed
                         !(:,:,5) = sfc pressure

  REAL, ALLOCATABLE :: stats_data(:,:,:)
                         !(:,1,1) = RMSE data (temp)
                         !(:,1,2) = RMSE data (dewpoint)
                         !(:,1,3) = RMSE data (sfc wind dir)
                         !(:,1,4) = RMSE data (sfc wind speed)
                         !(:,1,5) = RMSE data (sfc pressure)
                         !(:,2,1) = Bias data (temp)
                         !(:,2,2) = Bias data (dewpoint)
                         !(:,2,3) = Bias data (sfc wind dir)
                         !(:,2,4) = Bias data (sfc wind speed)
                         !(:,2,5) = Bias data (sfc pressure)
                                          ! etc.
!
!-----------------------------------------------------------------------
!
!  Namelists
!
!-----------------------------------------------------------------------
!

  INTEGER :: verifopt
  NAMELIST /verif_opt/ verifopt

  INTEGER :: sndopt
  CHARACTER (LEN=132) :: sndlist
  CHARACTER (LEN=132) :: sndrunname
  CHARACTER (LEN=132) :: snddomlist
  INTEGER :: proopt
  CHARACTER (LEN=132) :: prolist
  CHARACTER (LEN=132) :: prorunname
  CHARACTER (LEN=132) :: prodomlist
  INTEGER :: sfcopt
  CHARACTER (LEN=132) :: sfclist
  CHARACTER (LEN=132) :: sfcobsdir
  CHARACTER (LEN=132) :: sfcrunname
  CHARACTER (LEN=132) :: blackfile
  INTEGER :: precveropt
  CHARACTER (LEN=132) :: preclist
  CHARACTER (LEN=132) :: precrunname
  CHARACTER (LEN=132) :: precdomlist
  INTEGER :: mosopt
  CHARACTER (LEN=132) :: moslist
  CHARACTER (LEN=132) :: mosrunname
  CHARACTER (LEN=132) :: mosdomlist
  INTEGER :: arpsnn_opt
  CHARACTER (LEN=132) :: nnrunname
  CHARACTER (LEN=132) :: wtsdir 
  CHARACTER (LEN=132) :: nnoutputfn

  NAMELIST /single/ sndopt,sndlist,sndrunname,snddomlist,        &
                    proopt,prolist,prorunname,prodomlist,        &
                    sfcopt,sfclist,sfcobsdir,                    &
                    sfcrunname,blackfile,                        &
                    precveropt,preclist,precrunname,precdomlist, &
                    mosopt,moslist,mosrunname,mosdomlist,        &
                    arpsnn_opt,nnrunname,wtsdir,nnoutputfn

  INTEGER :: dummy
  NAMELIST /gridded/ dummy

!
!-----------------------------------------------------------------------
!
!  Work Arrays
!
!-----------------------------------------------------------------------
!
  REAL, ALLOCATABLE :: tem1(:,:,:)
  REAL, ALLOCATABLE :: tem2(:,:,:)
  REAL, ALLOCATABLE :: tem3(:,:,:)
  REAL, ALLOCATABLE :: tem4(:,:)
!
!-----------------------------------------------------------------------
!
!  Misc. internal variables
!
!-----------------------------------------------------------------------
!

  INTEGER :: i,j,k
  INTEGER :: nx,ny,nz
  INTEGER :: nzsoil
  INTEGER :: ireturn, istatus
  INTEGER :: hinfmt
  INTEGER :: nhisfile_max,nhisfile
  PARAMETER (nhisfile_max=200)
  CHARACTER (LEN=132) :: grdbasfn
  CHARACTER (LEN=132) :: hisfile(nhisfile_max)
  CHARACTER (LEN=4), PARAMETER :: tail=".hdf"

  INTEGER :: lengbf,nf,lenfil

  INTEGER, PARAMETER :: max_dim=200


  INTEGER, PARAMETER :: unum=5 ! unit number for namelist read
  INTEGER :: istat,sd_id,sds_id
  CHARACTER (LEN=132) :: hdfname

  INTEGER :: dims(2)
  INTEGER :: lname

!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
!  Beginning of executable code...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!

  WRITE(6,'(//5x,a)')                                                   &
      '###############################################################'
  WRITE(6,'(5x,a,/5x,a)')                                               &
      '#                                                             #', &
      '# Welcome to ARPSVERIF, a program that computes verification  #'
  WRITE(6,'(5x,a)')                                                     &
      '#                    of ARPS forecasts.                       #'
  WRITE(6,'(5x,a,/5x,a//)')                                             &
      '#                                                             #', &
      '###############################################################'

  READ (unum,verif_opt)
  WRITE(6,'(a)')'Namelist block verif_opt sucessfully read.'
  CALL get_input_file_names(hinfmt,grdbasfn,hisfile,nhisfile)
  READ (unum,single)
  WRITE(6,'(a)')'Namelist block single sucessfully read.'
  READ (unum,gridded)
  WRITE(6,'(a)')'Namelist block gridded sucessfully read.'

!
!-----------------------------------------------------------------------
!
!  Single-point verification
!
!-----------------------------------------------------------------------
!

  IF (verifopt.eq.1.or.verifopt.eq.3) THEN

  lengbf = len_trim(grdbasfn)

  CALL get_dims_from_data(hinfmt,grdbasfn(1:lengbf),                    &
       nx,ny,nz,nstyps, ireturn)

  IF( ireturn /= 0 ) THEN
    PRINT*,'Problem occured when trying to get dimensions from data.'
    PRINT*,'Program stopped.'
    STOP
  END IF

  WRITE(6,'(3(a,i5))') 'nx =',nx,', ny=',ny,', nz=',nz

  print*,'nstyps =', nstyps

!
!  ALLOCATE arrays
!

  ALLOCATE(x (nx),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:x")
  x = 0.0
  ALLOCATE(y (ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:y")
  y  = 0.0
  ALLOCATE(z (nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:z")
  z = 0.0
  ALLOCATE(zp (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:zp")
  zp = 0.0
  ALLOCATE(zpsoil (nx,ny,nzsoil),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:zpsoil")
  zpsoil = 0.0
  ALLOCATE(uprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:uprt")
  uprt = 0.0
  ALLOCATE(vprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:vprt")
  vprt  = 0.0
  ALLOCATE(wprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:wprt")
  wprt = 0.0
  ALLOCATE(hterain (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:hterain")
  hterain = 0.0
  ALLOCATE(ptprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:ptprt")
  ptprt  = 0.0
  ALLOCATE(pprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:pprt")
  pprt = 0.0
  ALLOCATE(qvprt (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qvprt")
  qvprt = 0.0
  ALLOCATE(qc (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qc")
  qc = 0.0
  ALLOCATE(qr (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qr")
  qr  = 0.0
  ALLOCATE(qi (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qi")
  qi = 0.0
  ALLOCATE(qs (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qs")
  qs = 0.0
  ALLOCATE(qh (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qh")
  qh = 0.0
  ALLOCATE(tke (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:tke")
  tke = 0.0
  ALLOCATE(kmh (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:kmh")
  kmh  = 0.0
  ALLOCATE(kmv (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:kmv")
  kmv = 0.0
  ALLOCATE(ubar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:ubar")
  ubar = 0.0
  ALLOCATE(vbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:vbar")
  vbar = 0.0
  ALLOCATE(wbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:wbar")
  wbar = 0.0
  ALLOCATE(ptbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:ptbar")
  ptbar  = 0.0
  ALLOCATE(pbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:pbar")
  pbar = 0.0
  ALLOCATE(rhobar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:rhobar")
  rhobar = 0.0
  ALLOCATE(qvbar (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qvbar")
  qvbar = 0.0
  ALLOCATE(soiltyp (nx,ny,nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:soiltyp")
  soiltyp = 0.0
  ALLOCATE(stypfrct (nx,ny,nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:stypfrct")
  stypfrct  = 0.0
  ALLOCATE(vegtyp (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:vegtyp")
  vegtyp = 0.0
  ALLOCATE(lai (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:lai")
  lai = 0.0
  ALLOCATE(roufns (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:roufns")
  roufns = 0.0
  ALLOCATE(veg (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:veg")
  veg = 0.0
  ALLOCATE(tsoil (nx,ny,nzsoil,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:tsoil")
  tsoil = 0.0
  ALLOCATE(qsoil (nx,ny,nzsoil,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qsoil")
  qsoil = 0.0
  ALLOCATE(wetcanp (nx,ny,0:nstyps),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:wetcanp")
  wetcanp  = 0.0
  ALLOCATE(snowdpth (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:snowdpth")
  snowdpth = 0.0
  ALLOCATE(raing (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:raing")
  raing = 0.0
  ALLOCATE(rainc (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:rainc")
  rainc = 0.0
  ALLOCATE(prcrate (nx,ny,4),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:prcrate")
  prcrate = 0.0
  ALLOCATE(radfrc (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:radfrc")
  radfrc = 0.0
  ALLOCATE(radsw (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:radsw")
  radsw = 0.0
  ALLOCATE(rnflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:rnflx")
  rnflx = 0.0
  ALLOCATE(radswnet (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:radswnet")
  radswnet = 0.0
  ALLOCATE(radlwin (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:radlwin")
  radlwin = 0.0
  ALLOCATE(usflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:usflx")
  usflx = 0.0
  ALLOCATE(vsflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:vsflx")
  vsflx = 0.0
  ALLOCATE(ptsflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:ptsflx")
  ptsflx = 0.0
  ALLOCATE(qvsflx (nx,ny),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:qvsflx")
  qvsflx = 0.0
  ALLOCATE(tem1 (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:tem1")
  tem1 = 0.0
  ALLOCATE(tem2 (nx,ny,nz),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:tem2")
  tem2 = 0.0
  ALLOCATE(model_data(sfcmax,nhisfile,5),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:model_data")
  model_data=0.0
  ALLOCATE(obsrv_data(sfcmax,nhisfile,5),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:obsrv_data")
  obsrv_data=-99.9  ! Set all obs equal to an initial missing value
  ALLOCATE(stats_data(nhisfile,2,5),STAT=istatus)
  CALL check_alloc_status(istatus, "arps:stats_data")
  stats_data=0.0

  readstns=.false.

  IF (sndopt.eq.1) THEN
  write (6,*) "Sounding verification is currently unavailable."
  write (6,*) "Program will terminate."
  STOP
  END IF

  IF (proopt.eq.1) THEN
  write (6,*) "Profiler verification is currently unavailable."
  write (6,*) "Program will terminate."
  STOP
  END IF

  IF (precveropt.eq.1) THEN
  write (6,*) "Precip. verification is currently unavailable."
  write (6,*) "Program will terminate."
  STOP
  END IF

  IF (mosopt.eq.1) THEN
  write (6,*) "MOS computation is currently unavailable."
  write (6,*) "Program will terminate."
  STOP
  END IF

  IF (arpsnn_opt.eq.1) THEN
  write (6,*) "The ARPS Neural Network option is currently unavailable."
  write (6,*) "Program will terminate."
  STOP
  END IF


  CALL his2ver(nx,ny,nz,nzsoil,x,y,z,zp,zpsoil,hterain,          & 
               uprt,vprt,wprt,ptprt,pprt,qvprt,                  & 
               qc,qr,qi,qs,qh,tke,kmh,kmv,                       &
               ubar,vbar,wbar,ptbar,pbar,rhobar,qvbar,           &
               nstyps,soiltyp,stypfrct,vegtyp,lai,roufns,        &
               veg,tsoil,qsoil,wetcanp,snowdpth,                 &
               raing,rainc,prcrate,radfrc,radsw,rnflx,           &
               radswnet,radlwin,                                 &
               usflx,vsflx,ptsflx,qvsflx,                        &
               hinfmt,grdbasfn,hisfile,nhisfile,                 &
               sndopt,sndlist,sndrunname,snddomlist,             &
               proopt,prolist,prorunname,prodomlist,             &
               sfcopt,sfclist,sfcobsdir,sfcrunname,blackfile,    &
               precveropt,preclist,precrunname,precdomlist,      &
               mosopt,moslist,mosrunname,mosdomlist,             &
               arpsnn_opt,nnrunname,wtsdir,nnoutputfn,           &
               model_data,obsrv_data)

!
! Calculate statistics on surface data.
!

   DO i=1,nhisfile

! RSME calculations
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,1)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,1)
     CALL root_mean_square(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,1,1))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,2)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,2)
     CALL root_mean_square(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,1,2))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,3)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,3)
     CALL root_mean_square(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,1,3))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,4)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,4)
     CALL root_mean_square(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,1,4))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,5)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,5)
     CALL root_mean_square(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,1,5))

! Bias calculations

     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,1)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,1)
     CALL bias_calc(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,2,1))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,2)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,2)
     CALL bias_calc(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,2,2))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,3)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,3)
     CALL bias_calc(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,2,3))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,4)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,4)
     CALL bias_calc(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,2,4))
     tem1=0.0
     tem2=0.0
     tem1(1:sfcstn,1,1)=obsrv_data(1:sfcstn,i,5)
     tem2(1:sfcstn,1,1)=model_data(1:sfcstn,i,5)
     CALL bias_calc(sfcstn,1,1,tem1,tem2,0,0,0,stats_data(i,2,5))
     
   END DO

!
! Write out all verification data into a specific HDF file.
!

   lname=LEN_TRIM(sfcrunname)
   hdfname=sfcrunname(1:lname)//".hdf"
   CALL hdfopen(hdfname,2,sd_id)
   dims(2)=sfcstn
   dims(1)=len(sfcstid(1))
   CALL write_sds_char(sds_id,sd_id,'sfcstid',sfcstid,2,dims)
   CALL hdfwrt2d(model_data(:,:,1),sfcmax,nhisfile,sd_id,0,0,'model_temp', &
                '2m ARPS Temperature','F',istatus)
   CALL hdfwrt2d(obsrv_data(:,:,1),sfcmax,nhisfile,sd_id,0,0,'obs_temp', &
                'Observation Temperature','F',istatus)
   CALL hdfwrt2d(model_data(:,:,2),sfcmax,nhisfile,sd_id,0,0,'model_dewp', &
                '2m ARPS Dewpoint','F',istatus)
   CALL hdfwrt2d(obsrv_data(:,:,2),sfcmax,nhisfile,sd_id,0,0,'obs_dewp', &
                'Observation Dewpoint','F',istatus)
   CALL hdfwrt2d(model_data(:,:,3),sfcmax,nhisfile,sd_id,0,0,'model_wdir', &
                'ARPS surface wind direction','m/s',istatus)
   CALL hdfwrt2d(obsrv_data(:,:,3),sfcmax,nhisfile,sd_id,0,0,'obs_wdir', &
                'Observation surface wind direction','m/s',istatus)
   CALL hdfwrt2d(model_data(:,:,4),sfcmax,nhisfile,sd_id,0,0,'model_wspd', &
                'ARPS surface wind speed','m/s',istatus)
   CALL hdfwrt2d(obsrv_data(:,:,4),sfcmax,nhisfile,sd_id,0,0,'obs_wspd', &
                'Observation surface wind speed','m/s',istatus)
   CALL hdfwrt2d(model_data(:,:,5),sfcmax,nhisfile,sd_id,0,0,'model_pres', &
                'ARPS surface pressure','mb',istatus)
   CALL hdfwrt2d(obsrv_data(:,:,5),sfcmax,nhisfile,sd_id,0,0,'obs_pres', &
                'Observation surface pressure','mb',istatus)
   CALL hdfwrt1d(stats_data(:,1,1),nhisfile,sd_id,'rmse_temp', &
                '2m Surface Temperature RMSE','none')
   CALL hdfwrt1d(stats_data(:,1,2),nhisfile,sd_id,'rmse_dewp', &
                '2m Surface Dewpoint RMSE','none')
   CALL hdfwrt1d(stats_data(:,1,3),nhisfile,sd_id,'rmse_wdir', &
                'Surface Wind Direction RMSE','none')
   CALL hdfwrt1d(stats_data(:,1,4),nhisfile,sd_id,'rmse_wspd', &
                'Surface Wind Speed RMSE','none')
   CALL hdfwrt1d(stats_data(:,1,5),nhisfile,sd_id,'rmse_pres', &
                'Surface Pressure RMSE','none')
   CALL hdfwrt1d(stats_data(:,2,1),nhisfile,sd_id,'bias_temp', &
                '2m Surface Temperature Bias','none')
   CALL hdfwrt1d(stats_data(:,2,2),nhisfile,sd_id,'bias_dewp', &
                '2m Surface Dewpoint Bias','none')
   CALL hdfwrt1d(stats_data(:,2,3),nhisfile,sd_id,'bias_wdir', &
                'Surface Wind Direction Bias','none')
   CALL hdfwrt1d(stats_data(:,2,4),nhisfile,sd_id,'bias_wspd', &
                'Surface Wind Speed Bias','none')
   CALL hdfwrt1d(stats_data(:,2,5),nhisfile,sd_id,'bias_pres', &
                'Surface Pressure Bias','none')
   CALL hdfclose(sd_id,istat)
  END IF

END PROGRAM arpsverif