program downscale_tau

! Purpose
! -------
! Interpolates climatological surface stresses from the Mk3L atmosphere model
! grid on to the grid used by the new, high-resolution ocean model. This
! interpolation is performed in exactly the same fashion as within the coupled
! model.
!
! Usage
! -----
! ./downsale_tau <in_file> <out_file>
!
! where:
!
! in_file	file containing climatological surface stresses from the AGCM
! out_file	output file
!
! History
! -------
! 2008 Feb 22	Steven Phipps	Original version

  implicit none

  include 'netcdf.inc'

  ! Define parameters
  integer, parameter :: imt = 130, &
                        jmt = 114, &
                        nx = 64, &
                        ny = 56
  real, parameter :: pi = 3.14159265, &
                     radian = 180.0/pi, &
                     radius = 6.37122e8, &
                     swldeg = -89.1331111924962
  real, dimension(58), parameter :: alatu = (/ -1.57079632342145, &
                                               -1.51519509774365, &
                                               -1.45959388227021, &
                                               -1.40399269429295, &
                                               -1.34839154842973, &
                                               -1.29279046039513, &
                                               -1.23718944745986, &
                                               -1.18158852900217, &
                                               -1.12598772719084, &
                                               -1.07038706785422, &
                                               -1.01478658161207, &
                                               -0.959186305381917, &
                                               -0.903586284425691, &
                                               -0.847986575189126, &
                                               -0.792387249328565, &
                                               -0.736788399559000, &
                                               -0.681190148374214, &
                                               -0.625592661443904, &
                                               -0.569996168916890, &
                                               -0.514401000689571, &
                                               -0.458807647669979, &
                                               -0.403216874610710, &
                                               -0.347629943659605, &
                                               -0.292049100964518, &
                                               -0.236478778882343, &
                                               -0.180929158247486, &
                                               -0.125430272644584, &
                                               -7.013097509103954E-002, &
                                               0.000000000000000E+000, &
                                               7.013097509103954E-002, &
                                               0.125430272644584, &
                                               0.180929158247486, &
                                               0.236478778882343, &
                                               0.292049100964518, &
                                               0.347629943659605, &
                                               0.403216874610710, &
                                               0.458807647669979, &
                                               0.514401000689571, &
                                               0.569996168916890, &
                                               0.625592661443904, &
                                               0.681190148374214, &
                                               0.736788399559000, &
                                               0.792387249328565, &
                                               0.847986575189126, &
                                               0.903586284425691, &
                                               0.959186305381917, &
                                               1.01478658161207, &
                                               1.07038706785422, &
                                               1.12598772719084, &
                                               1.18158852900217, &
                                               1.23718944745986, &
                                               1.29279046039513, &
                                               1.34839154842973, &
                                               1.40399269429295, &
                                               1.45959388227021, &
                                               1.51519509774365, &
                                               1.57079632342145, &
                                               1.62639754909925 /)

  ! Declare local variables
  character(len=80) :: in_file, out_file
  integer :: fileid, i, ia, iap1, j, ja, jap1, latdid, latvid, londid, &
             lonvid, mondid, month, monvid, status, tauxid, tauyid
  real :: sumdy
  real(kind=4), dimension(imt-2) :: lonuv
  real(kind=4), dimension(jmt-2) :: latuv
  real, dimension(jmt) :: dyt, phi
  real(kind=4), dimension(nx, ny, 12) :: staux, stauy
  real(kind=4), dimension(imt-2, jmt-2, 12) :: otx, oty

  ! ---------------------
  ! BEGIN EXECUTABLE CODE
  ! ---------------------

  ! ------------------------------------------------------------------------
  ! The following section calculates the values of PHI, the latitude of each
  ! velocity gridbox, in exactly the same way as in ocean.f
  ! ------------------------------------------------------------------------

  ! Set the meridional dimension of each tracer gridbox in degrees
  dyt(  2) =  1.5717758068763
  dyt(  3) =  1.5717758068763
  dyt(  4) =  1.5873125395736
  dyt(  5) =  1.5873125395736
  dyt(  6) =  1.5904318409297
  dyt(  7) =  1.5904318409297
  dyt(  8) =  1.5915276112852
  dyt(  9) =  1.5915276112852
  dyt( 10) =  1.5920305756336
  dyt( 11) =  1.5920305756336
  dyt( 12) =  1.5923010877064
  dyt( 13) =  1.5923010877064
  dyt( 14) =  1.5924626726494
  dyt( 15) =  1.5924626726494
  dyt( 16) =  1.5925666534402
  dyt( 17) =  1.5925666534402
  dyt( 18) =  1.5926373800807
  dyt( 19) =  1.5926373800807
  dyt( 20) =  1.5926875876849
  dyt( 21) =  1.5926875876849
  dyt( 22) =  1.5927244533195
  dyt( 23) =  1.5927244533195
  dyt( 24) =  1.5927522680130
  dyt( 25) =  1.5927522680130
  dyt( 26) =  1.5927737232154
  dyt( 27) =  1.5927737232154
  dyt( 28) =  1.5927905752292
  dyt( 29) =  1.5927905752292
  dyt( 30) =  1.5928040087625
  dyt( 31) =  1.5928040087625
  dyt( 32) =  1.5928148456915
  dyt( 33) =  1.5928148456915
  dyt( 34) =  1.5928236699541
  dyt( 35) =  1.5928236699541
  dyt( 36) =  1.5928309049419
  dyt( 37) =  1.5928309049419
  dyt( 38) =  1.5928368629406
  dyt( 39) =  1.5928368629406
  dyt( 40) =  1.5928417775583
  dyt( 41) =  1.5928417775583
  dyt( 42) =  1.5928458254894
  dyt( 43) =  1.5928458254894
  dyt( 44) =  1.5928491414079
  dyt( 45) =  1.5928491414079
  dyt( 46) =  1.5928518283288
  dyt( 47) =  1.5928518283288
  dyt( 48) =  1.5928539649014
  dyt( 49) =  1.5928539649014
  dyt( 50) =  1.5928556105851
  dyt( 51) =  1.5928556105851
  dyt( 52) =  1.5928568093168
  dyt( 53) =  1.5928568093168
  dyt( 54) =  1.5928575920821
  dyt( 55) =  1.5928575920821
  dyt( 56) =  1.5928579786506
  dyt( 57) =  1.5928579786506
  dyt( 58) =  1.5928579786506
  dyt( 59) =  1.5928579786506
  dyt( 60) =  1.5928575920821
  dyt( 61) =  1.5928575920821
  dyt( 62) =  1.5928568093168
  dyt( 63) =  1.5928568093168
  dyt( 64) =  1.5928556105851
  dyt( 65) =  1.5928556105851
  dyt( 66) =  1.5928539649014
  dyt( 67) =  1.5928539649014
  dyt( 68) =  1.5928518283288
  dyt( 69) =  1.5928518283288
  dyt( 70) =  1.5928491414079
  dyt( 71) =  1.5928491414079
  dyt( 72) =  1.5928458254894
  dyt( 73) =  1.5928458254894
  dyt( 74) =  1.5928417775583
  dyt( 75) =  1.5928417775583
  dyt( 76) =  1.5928368629406
  dyt( 77) =  1.5928368629406
  dyt( 78) =  1.5928309049419
  dyt( 79) =  1.5928309049419
  dyt( 80) =  1.5928236699541
  dyt( 81) =  1.5928236699541
  dyt( 82) =  1.5928148456915
  dyt( 83) =  1.5928148456915
  dyt( 84) =  1.5928040087625
  dyt( 85) =  1.5928040087625
  dyt( 86) =  1.5927905752292
  dyt( 87) =  1.5927905752292
  dyt( 88) =  1.5927737232154
  dyt( 89) =  1.5927737232154
  dyt( 90) =  1.5927522680130
  dyt( 91) =  1.5927522680130
  dyt( 92) =  1.5927244533195
  dyt( 93) =  1.5927244533195
  dyt( 94) =  1.5926875876849
  dyt( 95) =  1.5926875876849
  dyt( 96) =  1.5926373800807
  dyt( 97) =  1.5926373800807
  dyt( 98) =  1.5925666534402
  dyt( 99) =  1.5925666534402
  dyt(100) =  1.5924626726494
  dyt(101) =  1.5924626726494
  dyt(102) =  1.5923010877064
  dyt(103) =  1.5923010877064
  dyt(104) =  1.5920305756336
  dyt(105) =  1.5920305756336
  dyt(106) =  1.5915276112852
  dyt(107) =  1.5915276112852
  dyt(108) =  1.5904318409297
  dyt(109) =  1.5904318409297
  dyt(110) =  1.5873125395736
  dyt(111) =  1.5873125395736
  dyt(112) =  1.5717758068763
  dyt(113) =  1.5717758068763

  ! Convert DYT to centimetres
  dyt = dyt * radius / radian

  ! Calculate the latitude of each velocity gridbox
  phi(1) = swldeg / radian
  sumdy = phi(1)
  do j = 1, jmt
    if (j /= jmt) then
      sumdy = sumdy + dyt(j+1) / radius
      phi(j+1) = sumdy
    end if
  end do

  ! -----------------------------------------------------
  ! Get the climatological surface stresses from the AGCM
  ! -----------------------------------------------------

  ! Get the name of the input file
  call getarg(1, in_file)

  ! Get the climatological surface fluxes from the AGCM
  status = nf_open(in_file, nf_nowrite, fileid)
  status = nf_inq_varid(fileid, "taux", tauxid)
  status = nf_inq_varid(fileid, "tauy", tauyid)
  status = nf_get_var_real(fileid, tauxid, staux)
  status = nf_get_var_real(fileid, tauyid, stauy)
  status = nf_close(fileid)

  ! ------------------------------------------------------------------------
  ! The following section of code interpolates the surface stresses from the
  ! AGCM grid to the new, high-resolution OGCM grid.
  !
  ! These calculations are performed in exactly the same way as in ocntau.f.
  ! ------------------------------------------------------------------------

  ! Loop over months
  do month = 1, 12

    do j = 1, jmt-2
      ja = j  / 2
      jap1 = (j + 1) / 2

      do i = 1, imt-2
        ia = i / 2
        iap1 = (i + 1) / 2
        if (i .eq. 1) ia = (imt - 1)/2

        if (mod(i, 2) .eq. 0) then
          if (mod(j, 2) .eq. 0) then

            ! i even, j even
            otx(i, j, month) = staux(ia, ja, month)
            oty(i, j, month) = stauy(ia, ja, month)

          else

            ! i even, j odd
            if (j .eq. 1) then
              otx(i, j, month) = staux(ia, jap1, month)
              oty(i, j, month) = stauy(ia, jap1, month)
            else
              otx(i, j, month) = &
                (cos(alatu(ja+1)) * staux(ia, ja, month) + &
                 cos(alatu(ja+2)) * staux(ia, jap1, month)) / &
                (cos(alatu(ja+1)) + cos(alatu(ja+2)))
              oty(i, j, month) = &
                (cos(alatu(ja+1)) * stauy(ia, ja, month) + &
                 cos(alatu(ja+2)) * stauy(ia, jap1, month)) / &
                (cos(alatu(ja+1)) + cos(alatu(ja+2)))
            end if

          endif
        else
          if (mod(j, 2) .eq. 0) then

            ! i odd, j even
            otx(i, j, month) = 0.5 * (staux(ia, ja, month) + &
                                      staux(iap1, ja, month))
            oty(i, j, month) = 0.5 * (stauy(ia, ja, month) + &
                                      stauy(iap1, ja, month))

          else

            ! i odd, j odd
            if (j .eq. 1) then
              otx(i, j, month) = 0.5 * (staux(ia, jap1, month) + &
                                        staux(iap1, jap1, month))
              oty(i, j, month) = 0.5 * (stauy(ia, jap1, month) + &
                                        stauy(iap1, jap1, month))
            else
              otx(i, j, month) = &
                (cos(alatu(ja+1)) * staux(ia, ja, month) + &
                 cos(alatu(ja+1)) * staux(iap1, ja, month) + &
                 cos(alatu(ja+2)) * staux(ia, jap1, month) + &
                 cos(alatu(ja+2)) * staux(iap1, jap1, month)) / &
                (2.0 * (cos(alatu(ja+1)) + cos(alatu(ja+2))))
              oty(i, j, month) = &
                (cos(alatu(ja+1)) * stauy(ia, ja, month) + &
                 cos(alatu(ja+1)) * stauy(iap1, ja, month) + &
                 cos(alatu(ja+2)) * stauy(ia, jap1, month) + &
                 cos(alatu(ja+2)) * stauy(iap1, jap1, month)) / &
                (2.0 * (cos(alatu(ja+1)) + cos(alatu(ja+2))))
            end if

          end if
        end if
      end do
    end do

  end do

  ! --------------------------------------------------------
  ! Derive the axis data for the interpolated surface fluxes
  ! --------------------------------------------------------

  do i = 1, imt-2
    lonuv(i) = (real(i) - 1.0) * 360.0 / float(imt-2)
  end do
  do j = 1, jmt-2
    latuv(j) = phi(j+1) * radian
  end do

  ! --------------------------------
  ! Save the data to the output file
  ! --------------------------------
  
  ! Get the name of the output file
  call getarg(2, out_file)

  ! (1) Create netCDF file
  status = nf_create(out_file, nf_noclobber, fileid)

  ! (2) Define dimensions
  status = nf_def_dim(fileid, "lonuv", imt-2, londid)
  status = nf_def_dim(fileid, "latuv", jmt-2, latdid)
  status = nf_def_dim(fileid, "month", 12, mondid)

  ! (3) Define variables
  status = nf_def_var(fileid, "lonuv", nf_float, 1, londid, lonvid)
  status = nf_def_var(fileid, "latuv", nf_float, 1, latdid, latvid)
  status = nf_def_var(fileid, "month", nf_int, 1, mondid, monvid)
  status = nf_def_var(fileid, "taux", nf_float, 3, &
                      (/ londid, latdid, mondid /), tauxid)
  status = nf_def_var(fileid, "tauy", nf_float, 3, &
                      (/ londid, latdid, mondid /), tauyid)

  ! (4) Put attributes
  status = nf_put_att_text(fileid, lonvid, "long_name", 26, &
                           "Longitude of UV gridpoints")
  status = nf_put_att_text(fileid, latvid, "long_name", 25, &
                           "Latitude of UV gridpoints")
  status = nf_put_att_text(fileid, tauxid, "long_name", 17, &
                           "Zonal wind stress")
  status = nf_put_att_text(fileid, tauyid, "long_name", 22, &
                           "Meridional wind stress")
  status = nf_put_att_text(fileid, lonvid, "units", 12, "degrees_east")
  status = nf_put_att_text(fileid, latvid, "units", 13, "degrees_north")
  status = nf_put_att_text(fileid, tauxid, "units", 10, "dynes/cm^2")
  status = nf_put_att_text(fileid, tauyid, "units", 10, "dynes/cm^2")
  status = nf_put_att_text(fileid, monvid, "units", 6, "months")
  status = nf_put_att_text(fileid, lonvid, "point_spacing", 4, "even")
  status = nf_put_att_text(fileid, latvid, "point_spacing", 6, "uneven")
  status = nf_put_att_text(fileid, monvid, "point_spacing", 4, "even")
  status = nf_put_att_text(fileid, lonvid, "modulo", 1, " ")
  status = nf_put_att_text(fileid, monvid, "modulo", 1, " ")

  ! (5) Exit define mode
  status = nf_enddef(fileid)

  ! (6) Write data
  status = nf_put_var_real(fileid, lonvid, lonuv)
  status = nf_put_var_real(fileid, latvid, latuv)
  status = nf_put_var_int(fileid, monvid, (/ 1, 2, 3, 4, 5, 6, &
                                             7, 8, 9, 10, 11, 12 /))
  status = nf_put_var_real(fileid, tauxid, otx)
  status = nf_put_var_real(fileid, tauyid, oty)

  ! (7) Close output file
  status = nf_close(fileid)

end program downscale_tau