!$$$  MAIN PROGRAM DOCUMENTATION BLOCK
!
! MAIN PROGRAM:  GODAS_CMBDYSPRFS4
!   PRGMMR: David W. Behringer  ORG: NP23        DATE: 2003-07-25
!
! ABSTRACT:  Write temperature observations in form used by coupled GODAS
!
! PROGRAM HISTORY LOG:
! 2003-07-25  David W. Behringer - original C code
! 2010-09-27  David W. Behringer - added 2 lines after second reading of unit 11
!              to correct erroneous dropping of some profile files.
! 2012-01-22  David W. Behringer -Conversion of original C code to Fortran
! 2016-03-10  David W. Behringer - Added code to allow rescale of obs 
!              representation error. Region can be set by namelist.
!
! USAGE:
!   INPUT FILES:
!     UNIT 10  - NAMELIST FILE CONTAINING PRFS_NML
!     UNIT 11  - LIST IN ASCII OF DAILY TEMPERATURE PROFILE FILES IN IEEE
!     UNIT 21  - USED SUCCESSIVELY FOR DAILY PROFILE FILES, NOT SET
!                EXTERNALLY BY A SOFT LINK
!     grid_spec.nc - NETCDF GRID_SPEC FILE FOR OCEAN MODEL
!
!   OUTPUT FILES:
!     UNIT 31  - scratch FILE
!     UNIT 51  - TEMPERATURE FILE, tmpa.mom, AS USED BY GODAS
!     UNIT 06  - UNIT 6 (STANDARD PRINTFILE)
!
!   SUBPROGRAMS CALLED FROM PROGRAM: (LIST ALL CALLED FROM ANYWHERE IN CODES)
!     UNIQUE:    - getM4Grid, real_indx, inbnds
!     LIBRARY:
!       W3LIB    - w3tagb, w3tage, errexit
!
!   SUBPROGRAMS CALLED FROM MAIN: (LIST ALL CALLED FROM MAIN)
!     UNIQUE:    - getM4Grid, real_indx, inbnds
!     LIBRARY:
!       W3LIB    - w3tagb, w3tage, errexit
!
!   EXIT STATES:
!     COND =   0 - SUCCESSFUL RUN
!     COND =  11 - ERROR OPENING UNIT 11
!     COND =  12 - ERROR READING UNIT 11
!     COND =  21 - ERROR OPENING UNIT 12
!     COND =  22 - ERROR READING UNIT 12
!     COND =  31 - ERROR OPENING UNIT 13
!     COND =  32 - ERROR READING UNIT 13
!     COND =  51 - ERROR OPENING UNIT 51
!     COND =  52 - ERROR WRITING UNIT 51
!     COND =  61 - ERROR READING FROM COMMAND LINE
!
! REMARKS AND IMPORTANT LOCAL VARIABLES:
!     None
!
! ATTRIBUTES:  (LIST MACHINES FOR WHICH CODE IS USED AND CHECKED OUT)
!
!   MACHINE:  IBM WCOSS
!   LANGUAGE: F90
!
!
!$$$
!
      program cmbDysPrfs4
!
!  cmbDysPrfs4 combines profiles for use in assimilation
!
      implicit none
!
      include 'netcdf.inc'
!
      integer, parameter :: ndx=1500
      logical, parameter :: ecnst = .true., mkcr = .false.
      real, parameter :: stde=0.1, zeps=2.0
!     kmax = maximum number of model levels for assimilation
      integer, parameter :: kmax=30, kav=5
      real, parameter :: spv=999.999
      real, parameter :: ynlim=65.0
!
      character sid*2,dtyp*2,qkey*1,csign*8
      character dayFile*30
      real, allocatable, dimension(:) :: dz
      real, allocatable, dimension(:) :: xt, yt, zt, st, rev
      real, allocatable, dimension(:) :: a, z, s, tz, zw, sw
      real, allocatable, dimension(:,:,:) :: ac, sc
      integer, allocatable, dimension(:,:) :: smask
      integer :: nprf, nrd, n, nrjt
      integer :: imx, jmx, kmx
      integer :: i, j, k, kk, kw, kd
      integer iyear, idate, mon, day, ihr, min
      real x, y, xi, yj, xtmn, xtmx, se
!
      character(len=30) :: aname, dname, vname
      integer ncid, ndims, nvars, natts, idunlm, dsiz, nfstat
      integer nvdm, nvatts, vtype, atype, len
      integer, dimension(4)   :: start, count, vdm
      real(kind=8), allocatable, dimension(:,:)   :: nlev
!
      real :: lg0, lg1, lt0, lt1, efctr
      logical :: rescl_error, do_rscl
      namelist /prfs_nml/ lg0, lg1, lt0, lt1, efctr, rescl_error
!
      call w3tagb('GODAS_CMBDYSPRFS4',2003,0164,0164,'NP23')
!
! set namelist defaults and read namelist file
!
      rescl_error = .false.
      lg0 = 999.9
      lg1 = -999.9
      lt0 = 99.9
      lt1 = -99.9
      efctr = 1.0
!
      open(10)
      read(10, prfs_nml)
      close(10)
!
      write(6, prfs_nml)
      do_rscl = .false.
!
! open netCDF grid_spec first
! read model coordinates and mask
!
      call getM4Grid
!
      if (mkcr) call getCorrData
!
      allocate(st(kmx))
      allocate(rev(kmx))
      allocate(s(kmx))
      allocate(z(kmx))
      allocate(tz(kmx))
      allocate(zw(kmx))
      allocate(sw(kmx))
!
! open the input list file
!
      open (11,status='old',form='formatted', &
                 & access='sequential', err=110)
!
      open (31,status='replace',form='unformatted', &
                 & access='sequential', err=310)
!
      nprf = 0
      nrjt = 0
      nrd = 0
      do while (.true.)
        read(11,'(a)',end=10,err=120) dayFile
        open(21,file=trim(dayFile),form='unformatted', &
                 & access='sequential', err=210)
        do while (.true.)
          read(21,end=5,err=220) iyear,idate,csign,sid,dtyp, &
             & qkey,y,x,kd,(zt(k),st(k),k=1,kd)
          nrd = nrd + 1
!
          if (x < xtmn) x = x + 360.0
          if (x > xtmx) x = x - 360.0

          xi = real_indx(x, xt, imx)
          yj = real_indx(y, yt, jmx)
          if (xi .gt. 0.0 .and. yj .gt. 0.0 .and. y .le. ynlim) then
            do k=1,kd
              zw(k) = zt(k)
              sw(k) = st(k)
            end do

            kw = 1
            do k=1,kmx
              if (abs(zw(kw) - zt(k)) .le. zeps) then
                s(k) = sw(kw)
                z(k) = zw(kw)
                kw = kw + 1
              else
                s(k) = spv
                z(k) = zt(k)
              end if
              kk = k
              if (kw .gt. kd) exit
            end do
            kd = kk

            if (kd .gt. kmax) kd = kmax

            if (mkcr .and. dtyp .eq. '-1') call corrPrf(kd,xi,yj)

            if (kd > 1 .and. inbnds(xi,yj)) then

              if (rescl_error) then
                do_rscl = .false.
                if (x .ge. lg0 .and. x .le. lg1 .and. &
                              & y .ge. lt0 .and. y .le. lt1) then
                  do_rscl =.true.
                end if
              end if
              do k=1,kd
                st(k) = s(k)
                se = stde
                if (do_rscl) se = se*efctr
                rev(k) = 1.0 / (se*se)
              end do

              mon = idate/1000000;
              day = mod(idate,1000000)/10000;
              ihr  = mod(idate,10000)/100;
              min = mod(idate,100)
              write(31) iyear,mon,day,ihr,min,csign,dtyp,kd,x,y,(st(k),rev(k),k=1,kd)

              nprf = nprf + 1
            else
              nrjt = nrjt + 1
            end if
          end if
        end do
    5   continue
        close (12)
      end do
   10 continue
      close (11)
      rewind (31)
!
      open (51,status='replace',form='unformatted', &
                 & access='sequential', err=510)
      write(51,err=520) nprf
      do n=1,nprf
        read(31,err=320) iyear,mon,day,ihr,min,csign,dtyp,kd,x,y,(st(k),rev(k),k=1,kd)
        !!write(51,err=510) csign,dtyp
        write(51,err=510) iyear,mon,day,ihr,min,kd
        write(51,err=510) x,y
        write(51,err=510) (st(k),rev(k),k=1,kd)
      end do
!
      close(31)
      close(51)
!
      write(6,'(a,i5)') 'Profiles read:     ',nrd
      write(6,'(a,i5)') 'Profiles retained: ',nprf
      write(6,'(a,i5)') 'Profiles rejected: ',nrjt
!
  100 continue
!
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(0)
!
  110 write(6,'(a)') 'Error opening profile file on unit 11'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(11)
!
  120 write(6,'(a)') 'Error reading profile file on unit 11'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(12)
!
  210 write(6,'(a)') 'Error opening profile file on unit 21'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(21)
!
  220 write(6,'(a)') 'Error reading profile file on unit 21'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(22)
!
  310 write(6,'(a)') 'Error opening scratch file on unit 31'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(31)
!
  320 write(6,'(a)') 'Error writing scratch file on unit 31'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(32)
!
  330 write(6,'(a)') 'Error reading scratch file on unit 31'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(33)
!
  510 write(6,'(a)') 'Error opening profile file on unit 51'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(51)
!
  520 write(6,'(a)') 'Error writing profile file on unit 51'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(52)
!
  610 write(6,'(a)') 'Error reading date from command line'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(61)
!
      contains
!
! -------------------------------------------------------------- 
!
      subroutine getM4Grid

      nfstat = nf_open('grid_spec.nc', 0, ncid)
      if (nfstat .ne. NF_NOERR) then
        write(6,'(a,a)') 'Could not open grid_spec.nc'
        go to 210
      endif
!
! inquire about the file
!
      nfstat = nf_inq(ncid, ndims, nvars, natts, idunlm)
      if (nfstat .ne. NF_NOERR) then
        write(6,'(a)') 'Could not inquire about grid_spec.nc'
        go to 220
      endif
!
! inquire about dimensions
!
      do n=1,ndims
        nfstat = nf_inq_dim(ncid, n, dname, dsiz)
        if (nfstat .ne. NF_NOERR) then
          write(6,'(a)') 'Could not inquire about dimensions in grid_spec.nc'
          go to 220
        endif
        if (dname .eq. 'grid_x_T') then
          imx = dsiz
        else if (dname .eq. 'grid_y_T') then
          jmx = dsiz
        else if (dname .eq. 'zt') then
          kmx = dsiz
        endif
      enddo
!
! allocate some arrays
!
      allocate (xt(imx))
      allocate (yt(jmx))
      allocate (zt(kmx))
      allocate (nlev(imx,jmx))
      allocate (smask(imx,jmx))
!
! inquire about variables
! read some variables
!
      do n=1,nvars
        nfstat = nf_inq_var(ncid, n, vname, vtype, nvdm, vdm, nvatts)
        if (nfstat .ne. NF_NOERR) then
          write(6,'(a)') 'Could not inquire about variables in grid_spec.nc'
          go to 220
        endif
        if (vname .eq. 'grid_x_T') then
          start(1) = 1
          count(1) = imx
          nfstat = nf_get_vara_real(ncid, n, start, count, xt)
          if (nfstat .ne. NF_NOERR) then
            write(6,'(a)') 'Could not read XT in grid_spec.nc'
            go to 220
          endif
          xtmn = xt(1)
          xtmx = xt(imx)
        else if (vname .eq. 'grid_y_T') then
          start(1) = 1
          count(1) = jmx
          nfstat = nf_get_vara_real(ncid, n, start, count, yt)
          if (nfstat .ne. NF_NOERR) then
            write(6,'(a)') 'Could not read YT in grid_spec.nc'
            go to 220
          endif
        else if (vname .eq. 'zt') then
          start(1) = 1
          count(1) = kmx
          nfstat = nf_get_vara_real(ncid, n, start, count, zt)
          if (nfstat .ne. NF_NOERR) then
            write(6,'(a)') 'Could not read ZT in grid_spec.nc'
            go to 220
          endif
        else if (vname .eq. 'num_levels') then
          start(1) = 1
          count(1) = imx
          start(2) = 1
          count(2) = jmx
          nfstat = nf_get_vara_double(ncid, n, start, count, nlev)
          if (nfstat .ne. NF_NOERR) then
            write(6,'(a)') 'Could not read NLEV in grid_spec.nc'
            go to 220
          endif
        endif
      enddo
!
! close netcdf file
!
      nfstat = nf_close(ncid)
!
      smask = int(nlev+0.1)
!
      allocate(dz(kmx))
      dz(1) = 2.0*zt(1)
      do k=2,kmx
        dz(k) = 2.0*(zt(k) - zt(k-1)) - dz(k-1)
      end do
!
      return
!
  210 write(6,'(a)') 'Error opening grid_spec.nc file'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(21)
!
  220 write(6,'(a)') 'Error reading grid_spec.nc file'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(22)
!
      end subroutine getM4Grid
!
! -------------------------------------------------------------- 
!
      subroutine getCorrData
!
      integer :: i, j, kmc

      open (12,status='old',form='unformatted', &
                 & access='sequential', err=120)
      read (12, err=121, end=123) i,j,kmc
      if (i .ne. imx .and. j .ne. jmx) go to 122
      if (kmc .lt. kmx) go to 122
      allocate (ac(imx,jmx,kmc))
      allocate (sc(imx,jmx,kmc))
      read (12, err=121, end=123) ac
      read (12, err=121, end=123) sc
      close(12)
!
      return
!
  120 write(6,'(a)') 'Error opening correction file on unit 12'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(12)
!
  121 write(6,'(a)') 'Error reading correction file on unit 12'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(13)
!
  122 write(6,'(a)') 'Dimension mismatch of correction fields'
      write(6,'(2(a,2i4))') 'Correction: ',i,j,kmc,'  Model: ',imx,jmx,kmx
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(14)
!
  123 write(6,'(a)') 'Unexpected EOF in correction file on unit 12'
      call w3tage('GODAS_CMBDYSPRFS4')
      call errexit(15)
!
      end subroutine getCorrData
!
! -------------------------------------------------------------- 
!
      subroutine corrPrf(ktn, xi, yj)
!
      integer :: ktn, im, ip, jm, jp, i0, j0, k
      real :: xi, yj, dxm, dxp, dym, dyp, sdk, h, h0
    
      if (inbnds(xi, yj)) then
        ip = int(xi)
        im = ip - 1
        dxm = xi - real(ip)
        dxp = 1.0 - dxm
        jp = int(yj)
        jm = jp - 1
        dym = yj - real(jp)
        dyp = 1.0 - dym
    
        do k=1,ktn
          if (s(k) .ne. spv) then
            if (ac(im,jm,k) .ne. spv .and. ac(im,jp,k) .ne. spv .and. &
               & ac(ip,jp,k) .ne. spv .and. ac(ip,jm,k) .ne. spv) then
              s(k) = s(k) + ac(im,jm,k) * dxp * dyp + &
                 &          ac(im,jp,k) * dxp * dym + &
                 &          ac(ip,jp,k) * dxm * dym + &
                 &          ac(ip,jm,k) * dxm * dyp
              sdk = ac(im,jm,k) * dxp * dyp + &
                 &  ac(im,jp,k) * dxp * dym + &
                 &  ac(ip,jp,k) * dxm * dym + &
                 &  ac(ip,jm,k) * dxm * dyp
              rev(k) = 1.0/(stde*stde + sdk*sdk)
            else
              i0 = -1
              j0 = -1
              h0 = spv
              h = sqrt(dxm*dxm + dym*dym)
              if (ac(im,jm,k) .ne. spv .and. h < h0) then
                h0 = h
                i0 = im
                j0 = jm
              end if
              h = sqrt(dxm*dxm + dyp*dyp)
              if (ac(im,jp,k) .ne. spv .and. h < h0) then
                h0 = h
                i0 = im
                j0 = jp
              end if
              h = sqrt(dxp*dxp + dyp*dyp)
              if (ac(ip,jp,k) .ne. spv .and. h < h0) then
                h0 = h
                i0 = ip
                j0 = jp
              end if
              h = sqrt(dxp*dxp + dym*dym)
              if (ac(ip,jm,k) .ne. spv .and. h < h0) then
                h0 = h
                i0 = ip
                j0 = jm
              end if
              if (i0 .gt. 0 .and. j0 .gt. 0) then
                s(k) = s(k) + ac(i0,j0,k)
                sdk = ac(i0,j0,k)
                rev(k) = 1.0/(stde*stde + sdk*sdk)
              else
                s(k) = spv
                rev(k) = spv
              end if
            end if
          end if
        end do
      end if
!
      end subroutine corrPrf
!
! -------------------------------------------------------------- 
!
      function real_indx (p, pt, nmx)
!
      real p, pt(*)
      integer nmx
      real real_indx
!
      if (p .gt. pt(1) .and. p .le. pt(nmx)) then
        n = 1
        do while (pt(n) .lt. p)
          n = n + 1
        end do
        real_indx = float(n-1) + (p-pt(n-1)) / (pt(n)-pt(n-1))
      else
        real_indx = -1.0
      end if
!
      end function real_indx
!
! --------------------------------------------------------------
!
      function inbnds (x, y)
!
      real x, y
      logical inbnds
!
      if ((x .lt. 0.0 .and. y .lt. 0.0) .or. &
           & int(x) .gt. imx-1 .or. int(y) .gt. jmx-1) then
        inbnds = .false.
      else
        i = int(x)
        j = int(y)
        if (smask(i,j) .gt. 0 .or. smask(i+1,j) .gt. 0 .or. &
            & smask(i+1,j+1) .gt. 0 .or. smask(i,j+1) .gt. 0) then
          inbnds = .true.
        else
          inbnds = .false.
        end if
      end if
!
      end function inbnds
!
! -------------------------------------------------------------- 
!
      end program cmbDysPrfs4