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


PROGRAM avgverifgrid,1

!-----------------------------------------------------------------------
! 
! PURPOSE:
!
! Reads in HDF files produced by verifgrid, and calculates average
! RMSE and Bias statistics.  Also produces regional statistics.
!
! AUTHOR:  Eric Kemp, May 2000
!
!-----------------------------------------------------------------------
! 
! Use modules
!
!-----------------------------------------------------------------------

  USE verif

!-----------------------------------------------------------------------
!
! Variable declarations
!
!-----------------------------------------------------------------------
  
  IMPLICIT NONE
  
  CHARACTER*132 :: filedir ! temporary

  INTEGER,PARAMETER :: maxntime = 4

  INTEGER :: fdate(6)
  CHARACTER*4 :: amodel,agrid,fmodel,fgrid
  REAL :: adx,fdx
  INTEGER :: fnx,fny,vnx,vny
  INTEGER :: vmapproj
  REAL :: vtrulat1,vtrulat2,vtrulon,vsclfct,vctrlat,vctrlon
  REAL :: corner_lat(2,2),corner_lon(2,2)
  INTEGER :: timesec(maxntime)
  REAL,PARAMETER :: missing = -9999.
  INTEGER :: counter,avgcounter,avgcounterfiles
  REAL :: vdx,vdy
  
  INTEGER :: counter_p(nlevel,maxntime,nvar_p_stats)
  INTEGER :: counter_sfc(maxntime,nvar_sfc_stats)
  REAL,DIMENSION (nlevel,maxntime,nvar_p_stats) :: bias_p,rms_p
  REAL,DIMENSION (maxntime,nvar_sfc_stats) :: bias_sfc,rms_sfc
  REAL,ALLOCATABLE,DIMENSION (:,:,:,:,:) :: diff_p
  REAL,ALLOCATABLE,DIMENSION (:,:,:,:) :: diff_sfc


!..."Master" settings

  CHARACTER*4 :: mamodel,magrid,mfmodel,mfgrid
  REAL :: madx,mfdx
  INTEGER :: mfnx,mfny,mvnx,mvny
  INTEGER :: mvmapproj
  REAL :: mvtrulat1,mvtrulat2,mvtrulon,mvsclfct,mvctrlat,mvctrlon
  REAL :: mcorner_lat(2,2),mcorner_lon(2,2)
  INTEGER :: mtimesec(maxntime)
  INTEGER,ALLOCATABLE :: mcounter(:)
  REAL :: mvdx,mvdy

  INTEGER,ALLOCATABLE :: mcounter_p(:,:,:,:)
  INTEGER,ALLOCATABLE :: mcounter_sfc(:,:,:)
  REAL,ALLOCATABLE,DIMENSION (:,:,:,:) :: mbias_p,mrms_p
  REAL,ALLOCATABLE,DIMENSION (:,:,:) :: mbias_sfc,mrms_sfc
  REAL,ALLOCATABLE,DIMENSION (:,:,:,:,:,:) :: mdiff_p
  REAL,ALLOCATABLE,DIMENSION (:,:,:,:,:) :: mdiff_sfc

  REAL,DIMENSION (nlevel,maxntime,nvar_p_stats) :: avgbias_p,avgrms_p
  INTEGER,DIMENSION(nlevel,maxntime,nvar_p_stats) :: &
                avgbiasfiles_p,avgrmsfiles_p,avgcounterfiles_p
  REAL,DIMENSION (maxntime,nvar_sfc_stats) :: avgbias_sfc,avgrms_sfc
  INTEGER,DIMENSION(maxntime,nvar_sfc_stats) :: &
                avgbiasfiles_sfc,avgrmsfiles_sfc,avgcounterfiles_sfc
  INTEGER :: avgcounter_p(nlevel,maxntime,nvar_p_stats)
  INTEGER :: avgcounter_sfc(maxntime,nvar_sfc_stats)

  INTEGER,ALLOCATABLE :: mfdate(:,:)
!...

  CHARACTER*72 :: line72= &
'------------------------------------------------------------------------'

  CHARACTER*256 :: curfile 
  INTEGER :: i,j,k,l,m

!-----------------------------------------------------------------------
!
! Namelists
! 
!-----------------------------------------------------------------------

  INTEGER :: anx,any
  INTEGER :: numinfiles
  CHARACTER*256 :: infilename(90) ! May need to change this...
  INTEGER :: if_diff = 0
  INTEGER :: numdiffiles
  CHARACTER*256 :: hdiffile(90)

  NAMELIST /input/ anx,any,numinfiles,infilename,if_diff,numdiffiles, &
                   hdiffile

  CHARACTER*256 :: txtout,hdfout
  NAMELIST /output/ txtout,hdfout

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

   avgbias_p = 0
   avgbiasfiles_p = 0
   avgrms_p = 0
   avgrmsfiles_p = 0
   avgbias_sfc = 0
   avgbiasfiles_sfc = 0
   avgrms_sfc = 0
   avgrmsfiles_sfc = 0
   avgcounter = 0
   avgcounterfiles = 0
   avgcounter_p = 0
   avgcounterfiles_p = 0
   avgcounter_sfc = 0
   avgcounterfiles_sfc = 0

!-----------------------------------------------------------------------
!
! Read Namelists
! 
!-----------------------------------------------------------------------

  WRITE(6,*) 'Reading NAMELIST input'
  READ(5,input)
  WRITE(6,*) 'Reading NAMELIST output'
  READ(5,output)

  WRITE(6,*) 'anx = ',anx
  WRITE(6,*) 'any = ',any
  WRITE(6,*) 'numinfiles = ',numinfiles

  IF (numinfiles.gt.0) THEN
    DO i = 1,numinfiles
      WRITE(6,*)'i = ',i,' infilename(i) = ',infilename(i) 
    END DO
  END IF

  WRITE(6,*) 'if_diff = ',if_diff
  WRITE(6,*) 'numdiffiles = ',numdiffiles

  IF (numdiffiles.gt.0) THEN
    DO i = 1,numdiffiles
      WRITE(6,*)'i = ',i,' hdiffile(i) = ',hdiffile(i) 
    END DO
  END IF

!-----------------------------------------------------------------------
!
! Allocate arrays and begin processing the data.
! 
!-----------------------------------------------------------------------

  ALLOCATE(diff_p(anx,any,nlevel,maxntime,nvar_sfc_stats), &
           diff_sfc(anx,any,maxntime,nvar_sfc_stats),&
           mdiff_p(anx,any,nlevel,maxntime,nvar_sfc_stats,numinfiles),&
           mdiff_sfc(anx,any,maxntime,nvar_sfc_stats,numinfiles),&
           mcounter_p(nlevel,maxntime,nvar_p_stats,numinfiles),&
           mcounter_sfc(maxntime,nvar_sfc_stats,numinfiles),&
           mbias_p(nlevel,maxntime,nvar_p_stats,numinfiles),&
           mrms_p(nlevel,maxntime,nvar_p_stats,numinfiles),&
           mbias_sfc(maxntime,nvar_sfc_stats,numinfiles),&
           mrms_sfc(maxntime,nvar_sfc_stats,numinfiles), &
           mcounter(numinfiles),mfdate(6,numinfiles))

  DO i = 1,numinfiles

!-----------------------------------------------------------------------
!
!   Read the current file
! 
!-----------------------------------------------------------------------

    curfile = infilename(i)

    CALL rd_verif_stats_diff (curfile, if_diff, hdiffile, fdate, &
                     amodel,agrid,adx,anx,any, &
                     fmodel,fgrid,fdx, &
                     vdx, vdy, vnx, vny, vmapproj, &
                     vtrulat1, vtrulat2, vtrulon, vsclfct, vctrlat,&
                     vctrlon, corner_lat, corner_lon, &
                     nlevel, maxntime, nvar_p_stats, nvar_sfc_stats, &
                     timesec, pressure, missing, counter, &
                     counter_p, bias_p, rms_p, diff_p, &
                     counter_sfc, bias_sfc, rms_sfc, diff_sfc, &
                     varid_p, varname_p, varunit_p, &
                     varid_sfc, varname_sfc, varunit_sfc)

!-----------------------------------------------------------------------
!
!   If this is the first file, save the various map projection and
!   time information into the "master" arrays.   
! 
!-----------------------------------------------------------------------

    IF (i.EQ.1) THEN
      mamodel = amodel
      magrid = agrid
      mfmodel = fmodel
      mfgrid = fgrid
      madx = adx
      mfdx = fdx
      mfnx = fnx
      mfny = fny
      mvnx = vnx
      mvny = vny
      mvmapproj = vmapproj
      mvtrulat1 = vtrulat1
      mvtrulat2 = vtrulat2
      mvtrulon = vtrulon
      mvsclfct = vsclfct
      mvctrlat = vctrlat
      mvctrlon = vctrlon
      mcorner_lat = corner_lat
      mcorner_lon = corner_lon
      mtimesec = timesec
      mvdx = vdx
      mvdy = vdy      
    END IF
    mfdate(:,i) = fdate

!-----------------------------------------------------------------------
!
!   Compare the current map projection and time information with that
!   stored in the "master" arrays.  If they don't match, abort.
! 
!-----------------------------------------------------------------------

    IF ((mamodel.NE.amodel).OR.(magrid.NE.agrid).OR.&
        (mfmodel.NE.fmodel).OR.(mfgrid.NE.fgrid).OR.&
        (madx.NE.adx).OR.(mfdx.NE.fdx).OR.(mfnx.NE.fnx).OR.&
        (mfnx.NE.fny).OR.(mvnx.NE.vnx).OR.(mvny.NE.vny).OR.&
        (mvmapproj.NE.vmapproj).OR.(mvtrulat1.NE.vtrulat1).OR.&
        (mvtrulat2.NE.vtrulat2).OR.(mvtrulon.NE.vtrulon).OR.&
        (mvsclfct.NE.vsclfct).OR.(mvctrlat.NE.vctrlat).OR.&
        (mvctrlon.NE.mvctrlon).OR.&
        (mcorner_lat(1,1).NE.corner_lat(1,1)).OR.&
        (mcorner_lat(2,1).NE.corner_lat(2,1)).OR.&
        (mcorner_lat(1,2).NE.corner_lat(1,2)).OR.&
        (mcorner_lat(2,2).NE.corner_lat(2,2)).OR.&
        (mcorner_lon(1,1).NE.corner_lon(1,1)).OR.&
        (mcorner_lon(2,1).NE.corner_lon(2,1)).OR.&
        (mcorner_lon(1,2).NE.corner_lon(1,2)).OR.&
        (mcorner_lon(2,2).NE.corner_lon(2,2)).OR.&
        (mvdx.NE.vdx).OR.(mvdy.NE.vdy)) THEN

      WRITE(6,*)'ERROR: Grids do not match!  Aborting...'
      WRITE(6,*)'mamodel = ',TRIM(mamodel),' amodel = ',TRIM(amodel)
      WRITE(6,*)'magrid = ',TRIM(magrid),' agrid = ',TRIM(agrid)
      WRITE(6,*)'mfmodel = ',TRIM(mfmodel),' fmodel = ',TRIM(fmodel)
      WRITE(6,*)'mfgrid = ',TRIM(mfgrid),' fgrid = ',TRIM(fgrid)
      WRITE(6,*)'madx = ',madx,' adx = ',adx
      WRITE(6,*)'mfdx = ',mfdx,' fdx = ',fdx
      WRITE(6,*)'mfnx = ',mfnx,' fnx = ',fnx
      WRITE(6,*)'mfny = ',mfny,' fny = ',fny
      WRITE(6,*)'mvnx = ',mvnx,' vnx = ',vnx
      WRITE(6,*)'mvny = ',mvny,' vny = ',vny
      WRITE(6,*)'mvmapproj = ',mvmapproj,' vmapproj = ', &
                vmapproj
      WRITE(6,*)'mvtrulat1 = ',mvtrulat1,' vtrulat1 = ', &
                vtrulat1
      WRITE(6,*)'mvtrulat2 = ',mvtrulat2,' vtrulat2 = ', &
                vtrulat2
      WRITE(6,*)'mvtrulon = ',mvtrulon,' vtrulon = ',&
                vtrulon
      WRITE(6,*)'mvsclfct = ',mvsclfct,' vsclfct = ',&
                vsclfct
      WRITE(6,*)'mvctrlat = ',mvctrlat,' vctrlat = ',&
                vctrlat
      WRITE(6,*)'mvctrlon = ',mvctrlon,' vctrlon = ',&
                vctrlon
      WRITE(6,*)'mcorner_lat = ',mcorner_lat,' corner_lat = ',&
                corner_lat
      WRITE(6,*)'mcorner_lon = ',mcorner_lon,' corner_lon = ',&
                corner_lon
      WRITE(6,*)'mtimesec = ',mtimesec,' timesec = ',timesec
      WRITE(6,*)'mvdx = ',mvdx,' vdx = ',vdx
      WRITE(6,*)'mvdy = ',mvdy,' vdy = ',vdy
      STOP
    ENDIF
    DO j = 1,maxntime
      IF (mtimesec(j).NE.timesec(j)) THEN
        WRITE(6,*)'ERROR:  Times do not match!  Aborting...'
        WRITE(6,*)'mtimesec = ',mtimesec,' timesec = ',timesec
        STOP
      END IF
    END DO

!-----------------------------------------------------------------------
!
!   Copy the bias and rms scores to the "master" arrays, and then move
!   to the next file.
! 
!-----------------------------------------------------------------------

    mbias_p(:,:,:,i) = bias_p
    mrms_p(:,:,:,i) = rms_p
    mbias_sfc(:,:,i) = bias_sfc
    mrms_sfc(:,:,i) = rms_sfc
    mcounter(i) = counter
    mcounter_p(:,:,:,i) = counter_p
    mcounter_sfc(:,:,i) = counter_sfc
    mdiff_p(:,:,:,:,:,i) = diff_p
    mdiff_sfc(:,:,:,:,i) = diff_sfc

  END DO

!-----------------------------------------------------------------------
!
! Now calculate the average bias and rmse scores.
! 
!-----------------------------------------------------------------------

  DO i = 1, numinfiles
    IF (mcounter(i).NE.missing .AND. mcounter(i).NE.0) THEN
      avgcounter = avgcounter + mcounter(i)
      avgcounterfiles = avgcounterfiles + 1
    END IF
  END DO

  DO i = 1,nlevel
    DO j = 1,maxntime
      DO k = 1,nvar_p_stats
        DO l = 1,numinfiles
          IF (mbias_p(i,j,k,l).NE.missing .AND. &
              mrms_p(i,j,k,l).NE.missing) THEN
            avgbias_p(i,j,k) = avgbias_p(i,j,k) + mbias_p(i,j,k,l)
            avgbiasfiles_p(i,j,k) = avgbiasfiles_p(i,j,k) + 1
            avgrms_p(i,j,k) = avgrms_p(i,j,k) + mrms_p(i,j,k,l)
            avgrmsfiles_p(i,j,k) = avgrmsfiles_p(i,j,k) + 1
            avgcounter_p(i,j,k) = avgcounter_p(i,j,k) + &
              mcounter_p(i,j,k,l)
            avgcounterfiles_p(i,j,k) = avgcounterfiles_p(i,j,k) + 1
          END IF          
        END DO
      END DO
    END DO
  END DO

  DO i = 1,maxntime
    DO j = 1,nvar_sfc_stats
      DO k = 1,numinfiles
        IF (mbias_sfc(i,j,k).NE.missing .AND. &
            mrms_sfc(i,j,k).NE.missing) THEN
          avgbias_sfc(i,j) = avgbias_sfc(i,j) + mbias_sfc(i,j,k)
          avgbiasfiles_sfc(i,j) = avgbiasfiles_sfc(i,j) + 1
          avgrms_sfc(i,j) = avgrms_sfc(i,j) + mrms_sfc(i,j,k)
          avgrmsfiles_sfc(i,j) = avgrmsfiles_sfc(i,j) + 1
          avgcounter_sfc(i,j) = avgcounter_sfc(i,j) + &
            mcounter_sfc(i,j,k)
          avgcounterfiles_sfc(i,j) = avgcounterfiles_sfc(i,j) + 1
        END IF
      END DO
    END DO
  END DO

  DO i = 1,nlevel
    DO j = 1,maxntime
      DO k = 1,nvar_p_stats
        IF (avgbiasfiles_p(i,j,k).GT.0) THEN
          avgbias_p(i,j,k) = avgbias_p(i,j,k)/REAL(avgbiasfiles_p(i,j,k))
        ELSE
          avgbias_p(i,j,k) = missing
        END IF

        IF (avgrmsfiles_p(i,j,k).GT.0) THEN
          avgrms_p(i,j,k) = avgrms_p(i,j,k)/REAL(avgrmsfiles_p(i,j,k))
        ELSE
          avgrms_p(i,j,k) = missing
        END IF

        IF (avgcounterfiles_p(i,j,k).GT.0) THEN
          avgcounter_p(i,j,k) = &
            avgcounter_p(i,j,k)/REAL(avgcounterfiles_p(i,j,k))
        ELSE
          avgcounter_p(i,j,k) = 0
        END IF

      END DO
    END DO
  END DO

  DO i = 1,maxntime
    DO j = 1,nvar_sfc_stats

      IF (avgbiasfiles_sfc(i,j).GT.0) THEN
        avgbias_sfc(i,j) = avgbias_sfc(i,j)/REAL(avgbiasfiles_sfc(i,j))
      ELSE
        avgbias_sfc(i,j) = missing
      END IF

      IF (avgrmsfiles_sfc(i,j).GT.0) THEN
        avgrms_sfc(i,j) = avgrms_sfc(i,j)/REAL(avgrmsfiles_sfc(i,j))
      ELSE
        avgrms_sfc(i,j) = missing
      END IF

      IF (avgcounterfiles_sfc(i,j).GT.0) THEN
        avgcounter_sfc(i,j) = &
          avgcounter_sfc(i,j)/REAL(avgcounterfiles_sfc(i,j))
      ELSE
        avgcounter_sfc(i,j) = 0
      END IF

    END DO
  END DO

  IF (avgcounterfiles.GT.0) THEN
    avgcounter = avgcounter/avgcounterfiles
  ELSE
    avgcounter = 0
  END IF

!-----------------------------------------------------------------------
!
! Now write the average statstics to an output file.
! 
!-----------------------------------------------------------------------

  PRINT *, 'Writing text output to ', TRIM(txtout)
  OPEN(UNIT=13,FILE=txtout,STATUS="REPLACE")
      
  590 FORMAT (1x,a,i2.2,a)
  WRITE(13,590) 'Average statistics for ',numinfiles,' forecast runs.'
  WRITE(13,610) 'Forecast model/grid:', TRIM(fmodel), TRIM(fgrid)
  WRITE(13,626) fdx/1000.0

  WRITE(13,610) 'Analysis model/grid:', TRIM(amodel), TRIM(agrid)
  WRITE(13,626)  adx/1000.0
  WRITE(13,*)
  WRITE(13,*) 'Verification Region:' 
  WRITE(13,625) NINT((vnx+1)*vdx/1000.0), NINT((vny+1)*vdx/1000.0), &
                vdx/1000.0, vnx,vny
  WRITE(13,650) 'NW/NE', &
      corner_lat(1,2),corner_lon(1,2),corner_lat(2,2),corner_lon(2,2)
  WRITE(13,650) 'SW/SE', &
      corner_lat(1,1),corner_lon(1,1),corner_lat(2,1),corner_lon(2,1)
  WRITE(13,*) 'Average number of grid points in verif region: ', &
              avgcounter
  WRITE(13,*)

  DO i = 1,numinfiles
    WRITE(13,600) 'Forecast initialized ',mfdate(1,i),'-',mfdate(2,i),&  
      '-',mfdate(3,i),'.',mfdate(4,i),':',mfdate(5,i),':',mfdate(6,i)
  END DO
  
  DO l = 1,nvar_sfc_stats
    WRITE(13,'(A)') TRIM(line72)
    WRITE(13,810) TRIM(varname_sfc(l)), TRIM(varunit_sfc(l))
    WRITE(13,*) 'Time(hr)  Grid Points      Bias  RMS Error',&
                '  Fcsts'
    DO k = 1,maxntime
      WRITE(13,700) timesec(k)/3600, avgcounter_sfc(k,l), &
          avgbias_sfc(k,l), avgrms_sfc(k,l), avgbiasfiles_sfc(k,l)
    END DO
  END DO
  
  DO l = 1,nvar_p_stats
  DO m = 1,nlevel
    WRITE(13,'(A)') TRIM(line72)
    WRITE(13,810) TRIM(varname_p(l)), TRIM(varunit_p(l))
    WRITE(13,*) 'Level = ', pressure(m) / 100.0, ' mb'
    WRITE(13,*) 'Time(hr)  Grid Points      Bias  RMS Error',&
                '  Fcsts'
    DO k = 1,maxntime
      WRITE(13,700) timesec(k)/3600, avgcounter_p(m,k,l), &
          avgbias_p(m,k,l), avgrms_p(m,k,l),avgbiasfiles_p(m,k,l)
    END DO
  END DO
  END DO

  CALL wrt_verif_stats_diff (hdfout, 0, hdiffile, mfdate(:,1), &
                     mamodel,magrid,madx,anx,any, &
                     mfmodel,mfgrid,mfdx, &
                     mvdx, mvdy, mvnx, mvny, mvmapproj, &
                     mvtrulat1, mvtrulat2, mvtrulon, mvsclfct, &
                     mvctrlat, mvctrlon, &
                     mcorner_lat, mcorner_lon, &
                     nlevel, maxntime, nvar_p_stats, nvar_sfc_stats, &  
                     timesec, pressure, missing, avgcounter, &
                     avgcounter_p, avgbias_p, avgrms_p, diff_p, &
                     avgcounter_sfc, avgbias_sfc, avgrms_sfc, diff_sfc, &
                     varid_p, varname_p, varunit_p, &
                     varid_sfc, varname_sfc, varunit_sfc)

  600 FORMAT (1x,a21,i4.4,a1,i2.2,a1,i2.2,a1,i2.2,a1,i2.2,a1,i2.2)
  610 FORMAT (1X,A,1X,A,' / ',A)
  625 FORMAT (' Domain:',I5, ' x', I5, ' km, dx=', F5.1, &
              ' km (',I4,' x',I4,')' )
  626 FORMAT (' dx=', F5.1, ' km')
  650 FORMAT (1X,A,' corner lat/lon:', 2F10.3, 2X, 2F10.3)
  700 FORMAT (1x,i8,2x,i11,2x,f8.2,3x,f8.2,3x,I4)
  800 FORMAT (1x,i8,2x,i11,4x,f8.2,4x,f8.2,10x,f8.2)
  810 FORMAT ( 1X,A," (",A,")" )

END PROGRAM avgverifgrid