!
!##################################################################
!##################################################################
!######                                                      ######
!######             SUBROUTINE get_arps_dims_atts            ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!

SUBROUTINE get_arps_dims_atts(nchr,hinfmt,hisfile,lenfil,               & 1,6
                            nx,ny,nz,nzsoil,nstyps,                     &
                            year,month,day,hour,minute,second,time,     &
                            mapproj, sclfct,trulat1,trulat2,trulon,     &
                            ctrlat,ctrlon,dx,dy,ireturn)

!-----------------------------------------------------------------------
!
! PURPOSE:
!
!   Get ARPS dimensions and attributes from ARPS time-independent
!   history file.
!
!-----------------------------------------------------------------------
!
! Author: Yunheng Wang (09/01/2005)
!
!-----------------------------------------------------------------------
  IMPLICIT NONE

  INTEGER, INTENT(OUT) :: nchr
  INTEGER, INTENT(IN)  :: hinfmt
  CHARACTER(*), INTENT(IN)  :: hisfile
  INTEGER, INTENT(IN)  :: lenfil
  INTEGER, INTENT(OUT) :: nx,ny,nz,nzsoil,nstyps
  INTEGER, INTENT(OUT) :: year, month,day,hour,minute,second
  REAL,    INTENT(OUT) :: time
  INTEGER, INTENT(OUT) :: mapproj
  REAL,    INTENT(OUT) :: sclfct
  REAL,    INTENT(OUT) :: trulat1,trulat2,trulon
  REAL,    INTENT(OUT) :: ctrlat,ctrlon
  REAL,    INTENT(OUT) :: dx,dy
  INTEGER, INTENT(OUT) :: ireturn

!-----------------------------------------------------------------------
!
! Misc. local variables
!
!-----------------------------------------------------------------------

  INTEGER :: idummy 
  REAL    :: rdummy

  CHARACTER(LEN=40) :: fmtverin
  CHARACTER(LEN=10) :: tmunit
  CHARACTER(LEN=80) :: runname
  CHARACTER(LEN=12) :: label
  INTEGER           :: nocmnt, totin
  CHARACTER(LEN=80) :: cmnt(50)
  REAL              :: thisdmp, tstop
  REAL              :: latitud, xgrdorg, ygrdorg, umove, vmove

  REAL, ALLOCATABLE :: x(:)
  REAL, ALLOCATABLE :: y(:)

  INTEGER           :: i

!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Begin of executable code
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  IF( hinfmt == 1 ) THEN

    CALL getunit( nchr )

    OPEN(UNIT=nchr,FILE=hisfile(1:lenfil),STATUS='old',                 &
         FORM='unformatted',IOSTAT=ireturn)

    READ(nchr) fmtverin
    READ(nchr) runname
    READ(nchr) nocmnt
    IF( nocmnt > 0 ) THEN
      DO i=1,nocmnt
        READ(nchr) cmnt(i)
      END DO
    END IF

    READ(nchr) time,tmunit

    READ(nchr) nx, ny, nz,nzsoil

    READ(nchr)      idummy,idummy,idummy,idummy,idummy,                 &
                    idummy,idummy,idummy,idummy,totin,                  &
                    idummy,idummy,idummy,mapproj,month,                 &
                    day, year, hour, minute, second

    READ(nchr)      umove,  vmove, xgrdorg,ygrdorg,trulat1,             &
                    trulat2,trulon,sclfct,rdummy,rdummy,                &
                    rdummy,rdummy,rdummy,rdummy,rdummy,                 &
                    tstop,thisdmp,latitud,ctrlat,ctrlon

    IF ( totin /= 0 ) THEN


      READ(nchr) nstyps,idummy,idummy,idummy,idummy,                    &
                 idummy,idummy,idummy,idummy,idummy,                    &
                 idummy,idummy,idummy,idummy,idummy,                    &
                 idummy,idummy,idummy,idummy,idummy

      IF ( nstyps < 1 ) nstyps = 1

      READ(nchr) rdummy,rdummy,rdummy,rdummy,rdummy,                    &
                 rdummy,rdummy,rdummy,rdummy,rdummy,                    &
                 rdummy,rdummy,rdummy,rdummy,rdummy,                    &
                 rdummy,rdummy,rdummy,rdummy,rdummy
    END IF

    ALLOCATE(x(nx), STAT = idummy)
    ALLOCATE(y(ny), STAT = idummy)

    READ(nchr) label
    READ(nchr) x

    READ(nchr) label
    READ(nchr) y

    CLOSE (nchr)
    CALL retunit( nchr )

    dx = x(2) - x(1)
    dy = y(2) - y(1)

    DEALLOCATE(x,y)

  ELSE IF (hinfmt == 7 .OR. hinfmt == 8) THEN ! NetCDF format

    CALL netopen(hisfile(1:lenfil),'R',nchr)

    CALL net_getdims(nchr,nx,ny,nz,nzsoil,nstyps,ireturn)

    CALL net_getatts(nchr,runname,nocmnt,cmnt,dx,dy,                    &
                     year,month,day,hour,minute,second,thisdmp,tstop,   &
                     mapproj,sclfct,trulat1,trulat2,trulon,latitud,     &
                     ctrlat,ctrlon,xgrdorg,ygrdorg,umove,vmove,         &
                     idummy,idummy,idummy,idummy,idummy,idummy,         &
                     idummy,idummy,idummy,idummy,idummy,                &
                     idummy,idummy,idummy,idummy,ireturn)

!    CALL netreadTime(nchr,1,'Time',time)
    time = 0.0

    CALL netclose(nchr)

  ELSE

    WRITE(6,'(a,i3,a)')                                                 &
        ' Data format flag had an invalid value ',                      &
          hinfmt ,' program stopped.'
    CALL arpsstop('arpsstop called from get_arps_dims_atts wrong flag',1)

  END IF

  RETURN
END SUBROUTINE get_arps_dims_atts
!
!##################################################################
!##################################################################
!######                                                      ######
!######             SUBROUTINE write_static_attribute        ######
!######                                                      ######
!######                     Developed by                     ######
!######     Center for Analysis and Prediction of Storms     ######
!######                University of Oklahoma                ######
!######                                                      ######
!##################################################################
!##################################################################
!

SUBROUTINE write_static_attribute(nfid,io_form,start_date,              & 1,32
                   nx,ny,dx,dy,                                         &
                   mapproj,trulat1,trulat2,trulon,ctrlat,ctrlon,        &
                   lat_ll,lat_ul,lat_ur,lat_lr,                         &
                   lon_ll,lon_ul,lon_ur,lon_lr, istatus)
!
!-----------------------------------------------------------------------
!
! PURPOSE:
!   Write attributes of WRF static file.
!
!-----------------------------------------------------------------------
  USE wrf_metadata

  IMPLICIT NONE

  INTEGER, INTENT(IN)  :: nfid
  INTEGER, INTENT(IN)  :: io_form
  CHARACTER(*), INTENT(IN)  :: start_date
  INTEGER, INTENT(IN)  :: nx,ny
  REAL,    INTENT(IN)  :: dx,dy
  INTEGER, INTENT(IN)  :: mapproj
  REAL,    INTENT(IN)  :: trulat1,trulat2,trulon
  REAL,    INTENT(IN)  :: ctrlat, ctrlon
  REAL,    INTENT(IN)  :: lat_ll(4),lat_ul(4),lat_ur(4),lat_lr(4)
  REAL,    INTENT(IN)  :: lon_ll(4),lon_ul(4),lon_ur(4),lon_lr(4)
  INTEGER, INTENT(OUT) :: istatus

!-----------------------------------------------------------------------
!
! Misc. local variables
!
!-----------------------------------------------------------------------

  INTEGER           :: map_proj
  CHARACTER(LEN=20) :: map_string
  REAL              :: latcorns(16), loncorns(16)
  INTEGER           :: i,k

!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! Begin of executable code ...
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

  map_string(1:20) = ' '

  IF(ABS(mapproj) == 1) THEN
    map_proj   = 2
    map_string = 'POLAR STEREOGRAPHIC'
  ELSE IF(ABS(mapproj) == 2) THEN
    map_proj   = 1
    map_string = 'LAMBERT CONFORMAL'
  ELSE IF(ABS(mapproj) == 3) THEN
    map_proj = 3
    map_string = 'MERCATOR'
  ELSE
    WRITE(6,*) 'Unknown map projection, ', mapproj
    STOP
  END IF

  DO i = 1,4
    k = (i-1)*4+1
    latcorns(k) = lat_ll(i)
    loncorns(k) = lon_ll(i)
    k = k+1
    latcorns(k) = lat_ul(i)
    loncorns(k) = lon_ul(i)
    k = k+1
    latcorns(k) = lat_ur(i)
    loncorns(k) = lon_ur(i)
    k = k+1
    latcorns(k) = lat_lr(i)
    loncorns(k) = lon_lr(i)
  END DO

  IF (io_form == 7) CALL enter_ncd_define(nfid,istatus)

  CALL put_dom_ti_char(nfid,io_form,'TITLE',                            &
                       'WRF static file from ARPS2WRF',istatus)
  CALL put_dom_ti_char(nfid,io_form,'simulation_name',                  &
                       'WRFSTATIC',istatus)
  CALL put_dom_ti_char(nfid,io_form,'START_DATE',                       &
                       start_date(1:19),istatus)

  CALL put_dom_ti_integer(nfid,io_form,'DYN_OPT',      2,istatus)
  CALL put_dom_ti_integer(nfid,io_form,'WEST-EAST_GRID_DIMENSION',      &
                          nx, istatus)
  CALL put_dom_ti_integer(nfid,io_form,'SOUTH-NORTH_GRID_DIMENSION',    &
                          ny, istatus)

  CALL put_dom_ti_integer(nfid,io_form, 'GRID_ID',       1, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'PARENT_ID',     1, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'I_PARENT_START',1, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'J_PARENT_START',1, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'I_PARENT_END',  nx,istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'J_PARENT_END',  ny,istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'PARENT_GRID_RATIO',1,istatus)

  CALL put_dom_ti_real   (nfid,io_form, 'DX',dx,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'DY',dy,istatus)

  CALL put_dom_ti_varreal(nfid,io_form, 'corner_lats',latcorns,16,istatus)
  CALL put_dom_ti_varreal(nfid,io_form, 'corner_lons',loncorns,16,istatus)

  CALL put_dom_ti_real   (nfid,io_form, 'CEN_LAT',ctrlat,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'CEN_LON',ctrlon,istatus)

  CALL put_dom_ti_integer(nfid,io_form, 'FLAG_STATIC',1,istatus)

  CALL put_dom_ti_char(nfid,io_form,'map_projection',TRIM(map_string),  &
                       istatus)

  CALL put_dom_ti_integer(nfid,io_form, 'MAP_PROJ',     map_proj,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'MOAD_CEN_LAT', ctrlat,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'STAND_LON',    trulon,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'TRUELAT1',     trulat1,istatus)
  CALL put_dom_ti_real   (nfid,io_form, 'TRUELAT2',     trulat2,istatus)

  CALL put_dom_ti_integer(nfid,io_form, 'ISWATER',ISWATER,istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'ISICE',  ISICE,  istatus)
  CALL put_dom_ti_char   (nfid,io_form, 'MMINLU', 'USGS', istatus)

  IF (io_form == 7) CALL exit_ncd_define(nfid,istatus)

  RETURN
END SUBROUTINE write_static_attribute
!
! ================================================================
!

SUBROUTINE RDGEODAT(n2,n3,xt,yt,deltax,deltay,                          & 5,1
                  ofn,wvln,silwt,maxdatacat,                            &
                  datr,dats,datln,datlt,which_data, istat)

  IMPLICIT NONE

  INTEGER, INTENT(IN) ::  n2,n3
  REAL,    INTENT(IN) ::  deltax,deltay,wvln,silwt
              ! wvln = TOPTWVL_PARM_WRF from wrfsi.nl section &hgridspec
              ! siwt = SILAVWT_PARM_WRF                      
  REAL,    INTENT(IN) ::  xt(n2),yt(n3)
  INTEGER, INTENT(IN) ::  maxdatacat
  CHARACTER(LEN=*),INTENT(IN) ::  OFN

  REAL,    INTENT(OUT):: datr(n2,n3)
  REAL,    INTENT(OUT):: dats(n2,n3,maxdatacat)
  REAL,    INTENT(OUT):: datln(n2,n3)
  REAL,    INTENT(OUT):: datlt(n2,n3)

  LOGICAL, INTENT(OUT)::  which_data

  INTEGER, INTENT(OUT):: istat

!-----------------------------------------------------------------------
!
! local variables
!
!-----------------------------------------------------------------------

  INTEGER, PARAMETER :: IODIM = 5800000
    ! this parameter can be increased if we ever read data with
    ! resolution finer than 30 sec, or if the tilesize for 30s
    ! data becomes greater than 10x10 deg.
    !
  INTEGER :: lb,lbf
  INTEGER :: mof,np,niq,njq,nx,ny

  REAL    :: deltallo,deltaxq,deltayq, deltaxp,deltayp
  INTEGER :: no, iblksizo, isbego, iwbego
  REAL    :: rsoff,rwoff

  INTEGER :: lcat

  CHARACTER(LEN=180) ::TITLE

  REAL            :: std_lon = -100.0    ! not used anywhere
  REAL, PARAMETER :: erad    = 6371200.0 ! not used anywhere

  CHARACTER(LEN=180) :: tmpstr

!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
!
! begin of executable code
!
!@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

! *********************
  nx = n2-1
  ny = n3-1
! **********************

  lcat  = 1
  lbf   = LEN_TRIM(ofn)

  tmpstr(1:180) = ' '
  write(tmpstr,'(a)') ofn(1:lbf)

  title = ofn(1:lbf)//'HEADER'
  lb = LEN_TRIM(title)

  OPEN(29,STATUS='OLD',FILE=title(1:lb),FORM='FORMATTED')

  READ(29,*) iblksizo,no,isbego,iwbego,rsoff,rwoff
  print *,'title         = ',title
  print *,'rsoff,rwoff   = ',rsoff,rwoff
  print *,'isbego,iwbego = ',isbego,iwbego
  print *,'iblksizo,no   = ',iblksizo,no
  CLOSE(29)

  IF (no > 1) THEN
     deltallo = FLOAT(iblksizo)/FLOAT(no-1)
  ELSE IF(no == 1) THEN
     deltallo = FLOAT(iblksizo)/FLOAT(no)
  ELSE
     print*,'HEADER value NO = 0'
     istat = -1
     RETURN
  ENDIF

  mof = iodim/(no*no)

  IF (ofn(lbf:lbf) == 'G' .OR. ofn(lbf:lbf) == 'A') THEN  ! Green_frac or Albedo
    lcat=12
    IF (no == 1250) mof = 1
  END IF

! MOF determines the number of files held in buffer while reading
! DEM data; it saves some time when buffer data can be used instead
! of reading DEM file again. Originally MOF was 4.

  IF (mof > 10) mof = 5
      
  deltaxq = 0.5*wvln*deltax
  deltayq = 0.5*wvln*deltay
  print *,'deltaxq,deltayq=',deltaxq,deltayq

  niq = INT(FLOAT(nx)*deltax/deltaxq) + 4
  njq = INT(FLOAT(ny)*deltay/deltayq) + 4

  np  = MIN(10,MAX(1,INT(deltaxq/(deltallo*111000.))))
  print *,' np=',np

  deltaxp = deltaxq/FLOAT(np)
  deltayp = deltayq/FLOAT(np)

  CALL SFCOPQR(NO,MOF,NP,NIQ,NJQ,N2,N3,lcat,                            &
         XT,YT,90.,std_lon,ERAD,RWOFF,RSOFF,                            &
         DELTALLO,DELTAXP,DELTAYP,DELTAXQ,DELTAYQ,                      &
         IBLKSIZO,ISBEGO,IWBEGO,DATR,DATS,DATLN,DATLT,                  &
         tmpstr,WVLN,SILWT,which_data,maxdatacat,istat)       

  RETURN
END SUBROUTINE rdgeodat


SUBROUTINE get_path_to_soiltemp_1deg (path_soiltemp_1deg,istatus) 1

  IMPLICIT NONE
  CHARACTER*200 :: path_soiltemp_1deg
  INTEGER       :: istatus

  CHARACTER(LEN=200) :: path_to_soiltemp_1deg
  COMMON /lapscmn/ path_to_soiltemp_1deg
  
  path_soiltemp_1deg = path_to_soiltemp_1deg

  RETURN
END SUBROUTINE


SUBROUTINE interpolate_masked_val(nx_src, ny_src, lmask_src, data_src, & 1
                                 nx_out, ny_out, lmask_out, data_out, &
                                 isrcr, jsrcr, make_srcmask, &
                                 min_val, max_val, def_val, val_mask, &
                                 method)

    IMPLICIT none
    
    INTEGER, INTENT(IN)           :: nx_src
    INTEGER, INTENT(IN)           :: ny_src
    REAL, INTENT(INOUT)           :: lmask_src(nx_src,ny_src)
    REAL, INTENT(IN)              :: data_src(nx_src,ny_src)
    INTEGER, INTENT(IN)           :: nx_out, ny_out
    REAL, INTENT(IN)              :: lmask_out(nx_out,ny_out)
    REAL, INTENT(INOUT)             :: data_out(nx_out,ny_out)
    REAL, INTENT(IN)              :: isrcr(nx_out,ny_out)
    REAL, INTENT(IN)              :: jsrcr(nx_out,ny_out)
    LOGICAL, INTENT(IN)           :: make_srcmask
    REAL, INTENT(IN)              :: min_val, max_val, def_val, val_mask
    INTEGER, INTENT(IN)           :: method

    INTEGER                       :: i,j,k,l,ilo,jlo, ii, jj, kk, ll
    INTEGER                       :: search_rad
    INTEGER                       :: search_rad_max
    REAL, PARAMETER               :: bad_point = -99999.
    LOGICAL                       :: bad_points_flag
    LOGICAL                       :: fixed_bad
    INTEGER                       :: total_points
    INTEGER                       :: points_val_mask
    INTEGER                       :: points_skipped
    INTEGER                       :: num_to_fix
    INTEGER                       :: fixed_with_out
    INTEGER                       :: fixed_with_src
    INTEGER                       :: fixed_with_def
    INTEGER                       :: close_pts
    INTEGER                       :: ic,jc,iic,jjc
    REAL                          :: deltagx, deltagy
    REAL                          :: dix, djy
    REAL                          :: data_close(4)
    REAL                          :: distance(4)
    REAL                          :: distx,disty
    REAL                          :: sum_dist
    REAL                          :: a,b,c,d,e,f,g,h
    REAL                          :: stl(4,4)
    REAL                          :: valb
    REAL                          :: srcmask(nx_src,ny_src)

    LOGICAL                       :: wrapped_source

  INTEGER, PARAMETER          :: METHOD_NEAREST = 0
  INTEGER, PARAMETER          :: METHOD_LINEAR  = 1
  INTEGER, PARAMETER          :: METHOD_HIGHER = 2

    REAL                      :: oned

    IF ((MINVAL(isrcr).LT.1.0).OR. (MAXVAL(isrcr).GT.nx_src))THEN
      wrapped_source = .TRUE.
    ELSE
      wrapped_source = .FALSE.
    ENDIF
    ! Can we use the source data land mask that was input, or do we need to make it
    ! from the min_val/max_val arguments?  

    IF (make_srcmask) THEN
      PRINT '(A)', 'INTERPOLATE_MASKED_VAL: Making source data land mask...'
    
      ! This code has the flexibility to handled either water data points (lmask =0)
      ! or land points (lmask = 1). So if we are making the landmask using valid 
      ! range, but we do not know anything about the variable other than the 
      ! valid mask value, we need to figure out which points are 0 and which should be
      ! 1.  To do this, initialize the array to the invalid value, which we determine
      ! from the valid value.
      IF (val_mask .EQ. 0) THEN
        lmask_src(:,:) = 1
      ELSEIF (val_mask .EQ. 1) THEN
        lmask_src(:,:) = 0
      ELSE  
        lmask_src(:,:) = -1
      ENDIF
      
      ! Now figure out where to set the mask using a WHERE statement
      ! NOTE:  In this next line, if val_mask is 2, then the lmask_src
      ! is going to be set to 2, so we need to be careful in some of the 
      ! subsequent IF statements where lmask_src is compared to lmask_out
      WHERE((data_src .GE. min_val).AND.(data_src .LE. max_val)) lmask_src = val_mask
    ELSE
      PRINT '(A)', 'INTERPOLATE_MASKED: Using source landmask field.'
    ENDIF

   
    bad_points_flag = .false.
    
    ! Initialize counters
    total_points = 0
    points_val_mask = 0
    points_skipped = 0
    num_to_fix = 0
    fixed_with_out = 0
    fixed_with_src = 0
    fixed_with_def = 0

    ! Select interpolation method.  Putting the case statement out here
    ! increases the amount of replicated code but should be more efficient
    ! than checking this condition at every grid point.

    SELECT CASE(method)
  
      CASE(METHOD_NEAREST)
        ! Use nearest neigbor
        PRINT '(A)', 'Masked interpolation using nearest neighbor value...'
        out_j_loop_1: DO j = 1, ny_out
          out_i_loop_1: DO i = 1, nx_out

            total_points = total_points + 1
            ! We only need to process this point if the lmask_out is equal
            ! to val_mask.  For example, if one is processing soil parameters,
            ! which are only valid at land points (lmask = 1), then the user
            ! passes in 1. for the val_mask.  Any output point that is water
            ! (lmask = 0) will then be skipped.  During this loop, if we have
            ! points that cannot be properly assigned, we will mark them as bad
            ! and set the bad_points_lag.  Exception is if val_mask = 2, which
            ! implies that we are doing masked interpolation for both land
            ! and water, but allowing only water points to influence water
            ! points and land points to influence landpoints.

            IF ((lmask_out(i,j) .EQ. val_mask).OR.(val_mask .EQ. 2)) THEN
              ! Process this point 
              points_val_mask = points_val_mask + 1
              ilo = NINT(isrcr(i,j))
              ! Account for horizontal wrapping as in the case
              ! of global data sets.  This is the only time
              ! it is possible for ilo < 1 or ilo > nx_src
              IF (ilo .LT.1) ilo = nx_src
              IF (ilo .GT. nx_src) ilo = 1
                
              jlo = NINT(jsrcr(i,j))
        
              ! See if this point can be used
              IF ((lmask_src(ilo,jlo).EQ. lmask_out(i,j)).OR. &
                  (lmask_src(ilo,jlo).EQ.2)) THEN
                data_out(i,j) = data_src(ilo,jlo)
              ELSE
                data_out(i,j) = bad_point
                num_to_fix = num_to_fix + 1
                bad_points_flag = .true.
              ENDIF 
            ELSE
              ! The output grid does not require a value for this point
              ! But do not zero out in case this is a field begin
              ! done twice (once for water and once for land, e.g.
              ! SKINTEMP
              !data_out(i,j) = 0.
              points_skipped = points_skipped + 1
            ENDIF
          ENDDO out_i_loop_1
        ENDDO out_j_loop_1
      
      CASE (METHOD_LINEAR)
        ! Use a 4-point interpolation
        PRINT '(A)', 'Masked interpolation using 4-pt linear interpolation...'
        deltagx = 1.
        deltagy = 1.
        out_j_loop_2: DO j = 1, ny_out
          out_i_loop_2: DO i = 1, nx_out

            total_points = total_points + 1
            ! We only need to process this point if the lmask_out is equal
            ! to val_mask.  For example, if one is processing soil parameters,
            ! which are only valid at land points (lmask = 1), then the user
            ! passes in 1. for the val_mask.  Any output point that is water
            ! (lmask = 0) will then be skipped.  During this loop, if we have
            ! points that cannot be properly assigned, we will mark them as bad
            ! and set the bad_points_lag.

            IF ((lmask_out(i,j) .EQ. val_mask).OR.(val_mask .EQ. 2)) THEN
              ! Process this point
              points_val_mask = points_val_mask + 1
               
              ! If ilo < 1 or > nx_src, this is a wrapped source dataset

              ilo = FLOOR(isrcr(i,j))
              IF (ilo .EQ. 0) ilo = nx_src
              jlo = MIN(FLOOR(jsrcr(i,j)),ny_src-1)
              dix = isrcr(i,j) - FLOAT(ilo)
              IF (dix .LT.0) dix = dix + FLOAT(nx_src)
              djy = jsrcr(i,j) - FLOAT(jlo)
 
              ! Loop around the four surrounding points
              ! and count up the number of points we can use based
              ! on common mask value
              close_pts = 0
              sum_dist = 0.
              outer_four_j: DO jc = 0,1
                outer_four_i: DO ic = 0,1
                  iic = ilo + ic
                  IF(iic .GT. nx_src) iic = iic - nx_src
                  jjc = jlo + jc
                  IF ((lmask_src(iic,jjc).EQ. lmask_out(i,j)).OR. &
                      (lmask_src(iic,jjc).EQ.2)) THEN
                    close_pts = close_pts + 1
                    data_close(close_pts) = data_src(iic,jjc)
                       
                    ! Compute distance to this valid point
                    ! in grid units and add to sum of distances (actually,
                    ! we are doing a weight, which is inversely proportional
                    ! to distance)
                    IF (ic .EQ. 0) THEN
                      distx = deltagx - dix
                    ELSE
                      distx =  dix
                    ENDIF
                    IF (jc .EQ. 0) THEN
                      disty = deltagy - djy
                    ELSE
                      disty = djy
                    ENDIF  
                    distance(close_pts) = SQRT(distx**2+disty**2)
                    sum_dist = sum_dist + distance(close_pts)
                  ENDIF 
                ENDDO outer_four_i
              ENDDO outer_four_j
 
              ! Did we find at least one point in the surrounding four 
              ! that was usable?

              IF (close_pts .GT. 0) THEN
               
                ! If we have all four points, then do bilinear interpolation
                IF (close_pts .EQ. 4) THEN
                   data_out(i,j) = ((deltagx - dix)*((deltagy-djy)*data_close(1) &
                                 + djy*data_close(3)) &
                                 + dix*((deltagy-djy)*data_close(2) &
                                 + djy*data_close(4))) &
                                 / (deltagx * deltagy)
                ELSE IF ((close_pts .GT. 1).AND.(close_pts .LT. 4)) THEN

                  ! Simple distance-weighted average by computing
                  ! the sum of all distances to each point and using
                  ! each individual distance divided by the total
                  ! distance as the weighting

                  data_out(i,j) = 0.
                  DO k = 1, close_pts
                    data_out(i,j) = data_out(i,j) + &
                                    (distance(k)/sum_dist) * data_close(k)
                  ENDDO
                ELSE
                  ! Set output value = to one point we found
                  data_out(i,j) = data_close(1)
                ENDIF
              ELSE
                bad_points_flag = .true.
                data_out(i,j) = bad_point
                num_to_fix = num_to_fix + 1   
              ENDIF 
            ELSE
              ! The output grid does not require a value for this point
              ! But do not zero out in case this is a field begin                            
              ! done twice (once for water and once for land, e.g.   
              ! SKINTEMP
              points_skipped = points_skipped + 1
            ENDIF
          ENDDO out_i_loop_2
        ENDDO out_j_loop_2                                        

      CASE (METHOD_HIGHER)
        ! 16-point interpolation 
        out_j_loop_3: DO j = 1, ny_out
          out_i_loop_3: DO i = 1, nx_out

            total_points = total_points + 1
            ! We only need to process this point if the lmask_out is equal
            ! to val_mask.  For example, if one is processing soil parameters,
            ! which are only valid at land points (lmask = 1), then the user
            ! passes in 1. for the val_mask.  Any output point that is water
            ! (lmask = 0) will then be skipped.  During this loop, if we have
            ! points that cannot be properly assigned, we will mark them as bad
            ! and set the bad_points_lag.

            IF ((lmask_out(i,j) .EQ. val_mask).OR.(val_mask .EQ. 2)) THEN
              ! Process this point
              points_val_mask = points_val_mask + 1   
 
              ! Do a 4x4 loop around in the input data around the output
              ! point to get our 16 points of influence.  Only use those
              ! that are appropriately masked
              valb = 0.
              close_pts = 0
              ilo = INT(isrcr(i,j)+0.00001)
              jlo = INT(jsrcr(i,j)+0.00001)
              dix = isrcr(i,j) - ilo
              djy = jsrcr(i,j) - jlo
              IF ( (ABS(dix).GT.0.0001).OR.(ABS(djy).GT.0.0001) ) THEN
                ! Do the interpolation loop
                stl(:,:) = 0.
                loop_16_1: DO k = 1,4
                  kk = ilo + k - 2
                  IF ((kk .LT. 1).OR.(kk .GT. nx_src)) THEN
                    IF (.NOT. wrapped_source) THEN
                      CYCLE loop_16_1
                    ELSE
                      IF (kk .LT. 1) THEN 
                        kk = kk + nx_src
                      ELSE
                        kk = kk - nx_src 
                      ENDIF
                    ENDIF
                  ENDIF
                  loop_16_2: DO l = 1, 4
                    ll = jlo + l - 2
                    IF ((ll .LT. 1).OR.(ll .GT. ny_src)) CYCLE loop_16_2

                    ! Check land mask at this source point
                    IF ((lmask_src(kk,ll).NE. lmask_out(i,j)).AND. &
                        (lmask_src(kk,ll).NE.2))  CYCLE loop_16_2
                    ! If we are here, then mask tests passed
                    stl(k,l) = data_src(kk,ll) 
                    IF ( (stl(k,l) .EQ. 0.).AND.(min_val.LE.0.).AND. &
                                                (max_val.GE.0.) ) THEN
                      stl = 1.E-5
                    ENDIF
                    close_pts = close_pts + 1
                  ENDDO loop_16_2
                ENDDO loop_16_1
  
                ! Did we find any valid points?

                IF ( (close_pts .GT. 0).AND. ( &
                  (stl(2,2).GT.0.).AND.(stl(2,3).GT.0.).AND. &
                  (stl(3,2).GT.0.).AND.(stl(3,3).GT.0.)  ) ) THEN
                  a = oned(dix,stl(1,1),stl(2,1),stl(3,1),stl(4,1))
                  b = oned(dix,stl(1,2),stl(2,2),stl(3,2),stl(4,2))
                  c = oned(dix,stl(1,3),stl(2,3),stl(3,3),stl(4,3))
                  d = oned(dix,stl(1,4),stl(2,4),stl(3,4),stl(4,4))
                  valb = oned(djy,a,b,c,d)
                  IF (close_pts .NE. 16) THEN
                    e = oned(djy,stl(1,1),stl(1,2),stl(1,3),stl(1,4))
                    f = oned(djy,stl(2,1),stl(2,2),stl(2,3),stl(2,4))
                    g = oned(djy,stl(3,1),stl(3,2),stl(3,3),stl(3,4))
                    h = oned(djy,stl(4,1),stl(4,2),stl(4,3),stl(4,4))
                    valb = (valb+oned(dix,e,f,g,h)) * 0.5
                  ENDIF
                  data_out(i,j) = valb
            
                ELSE
                  bad_points_flag = .true.
                  data_out(i,j) = bad_point
                  num_to_fix = num_to_fix + 1
                ENDIF
              ELSE
                ! We are right on a source point, so try to use it
                IF ((lmask_src(ilo,jlo).EQ.lmask_out(i,j)).OR.&
                    (lmask_src(ilo,jlo).EQ.2)) THEN
                  data_out(i,j) = data_src(ilo,jlo)
                ELSE
                  bad_points_flag = .true.
                  data_out(i,j) = bad_point
                  num_to_fix = num_to_fix + 1 
                ENDIF
              ENDIF
            ELSE
              ! The output grid does not require a value for this point
              !data_out(i,j) = 0.
              points_skipped = points_skipped + 1      
            ENDIF
          ENDDO out_i_loop_3
        ENDDO out_j_loop_3        

    END SELECT

     ! Do we need to correct bad points?
  
    IF (bad_points_flag) THEN
     
      search_rad_max = 10
      fix_bad_j: DO j = 1, ny_out
        fix_bad_i: DO i = 1, nx_out
 
          IF (data_out(i,j).NE. bad_point) CYCLE fix_bad_i
          
          ! First, search for nearest non-bad point in the output domain
          ! which is usually higher resolution. 
          fixed_bad = .false.
          search_out_loop: DO search_rad = 1, search_rad_max
            search_out_j: DO ll = -(search_rad-1), (search_rad-1),1
              jj = j + ll
              IF ((jj .LT. 1).OR.(jj .GT. ny_out)) CYCLE search_out_j
              search_out_i: DO kk = -(search_rad), search_rad, 1
                 ii = i + kk
                 IF ((ii .LT. 1).OR.(ii .GT. nx_out)) CYCLE search_out_i
                 IF ((data_out(ii,jj).NE.bad_point).AND. &
                    (lmask_out(ii,jj) .EQ. lmask_out(i,j)) ) THEN
                  data_out(i,j) = data_out(ii,jj)
                  fixed_bad = .true.
                  fixed_with_out = fixed_with_out + 1
                  EXIT search_out_loop
                ENDIF
              ENDDO search_out_i
            ENDDO search_out_j
          ENDDO search_out_loop

          ! Did we fix the point?  If not, then do same search on src data.
          IF (.NOT. fixed_bad) THEN
            search_rad_max = 10
            search_src_loop: DO search_rad = 1, search_rad_max
              search_src_j: DO ll = -(search_rad-1), (search_rad-1),1
                jj = NINT(jsrcr(i,j)) + ll
                IF ((jj .LT. 1).OR.(jj .GT. ny_src)) CYCLE search_src_j
                search_src_i: DO kk = -(search_rad), search_rad, 1
                   ii = NINT(isrcr(i,j)) + kk
                   IF ((ii .LT. 1).OR.(ii .GT. nx_src)) THEN
                     IF (.NOT. wrapped_source) THEN
                       CYCLE search_src_i
                     ELSE
                       IF (ii.LT.1) THEN
                         ii = nx_src + ii
                       ELSE
                         ii = ii - nx_src
                       ENDIF
                     ENDIF
                   ENDIF
                   IF ((lmask_src(ii,jj).EQ.lmask_out(i,j)).OR. &
                       (lmask_src(ii,jj).EQ.2)) THEN
                     data_out(i,j) = data_src(ii,jj)
                     fixed_bad = .true.
                     fixed_with_src = fixed_with_src + 1
                     EXIT search_src_loop
                   ENDIF
                ENDDO search_src_i
              ENDDO search_src_j
            ENDDO search_src_loop
          ENDIF
          ! Now is the point fixed?  If not, we have to use a default value.
          IF (.NOT.fixed_bad) THEN
            fixed_with_def = fixed_with_def + 1
            data_out(i,j) = def_val
            PRINT '(A,F10.3,A,2I5)', 'INTERPOLATE_MASKED: Bogus value of ', def_val, &
                ' used at point ', i, j
          ENDIF
         
        ENDDO fix_bad_i
      ENDDO fix_bad_j
    ENDIF
    PRINT '(A)',     '----------------------------------------'
    PRINT '(A)',     'MASKED INTERPOLATION SUMMARY: '
    PRINT '(A,I10)', '  TOTAL POINTS IN GRID:       ', total_points
    PRINT '(A,I10)', '  POINTS NEEDING VALUES:      ', points_val_mask
    PRINT '(A,I10)', '  POINTS NOT REQUIRED:        ', points_skipped
    PRINT '(A,I10)', '  POINTS NEEDING FIX:         ', num_to_fix
    PRINT '(A,I10)', '  POINTS FIXED WITH OUT GRID: ', fixed_with_out
    PRINT '(A,I10)', '  POINTS FIXED WITH SRC GRID: ', fixed_with_src
    PRINT '(A,I10)', '  POINTS FIXED WITH DEF VAL:  ', fixed_with_def
    PRINT '(A)',     '----------------------------------------'
    RETURN
END SUBROUTINE interpolate_masked_val        

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


FUNCTION oned(x,a,b,c,d)

      IMPLICIT NONE

      REAL :: x,a,b,c,d,oned

      oned = 0.

      IF      ( x .EQ. 0. ) THEN
         oned = b
      ELSE IF ( x .EQ. 1. ) THEN
         oned = c
      END IF

      IF(b*c.NE.0.) THEN
         IF ( a*d .EQ. 0. ) THEN
            IF      ( ( a .EQ. 0 ) .AND. ( d .EQ. 0 ) ) THEN
               oned = b*(1.0-x)+c*x
            ELSE IF ( a .NE. 0. ) THEN
               oned = b+x*(0.5*(c-a)+x*(0.5*(c+a)-b))
            ELSE IF ( d .NE. 0. ) THEN
               oned = c+(1.0-x)*(0.5*(b-d)+(1.0-x)*(0.5*(b+d)-c))
            END IF
         ELSE
            oned = (1.0-x)*(b+x*(0.5*(c-a)+x*(0.5*(c+a)-b)))+ &
                   x*(c+(1.0-x)*(0.5*(b-d)+(1.0-x)*(0.5*(b+d)-c))) 
         END IF
      END IF

END FUNCTION oned

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


SUBROUTINE latlon_2_llij(np,glat,glon,lli,llj,lat0,lon0,dlat,dlon,cgrddef) 1

  IMPLICIT NONE
  INTEGER, INTENT(IN)  :: np
  REAL,    INTENT(IN)  :: glat(np), glon(np)
  REAL,    INTENT(OUT) :: lli(np),  llj(np)
  REAL,    INTENT(IN)  :: lat0, lon0
  REAL,    INTENT(IN)  :: dlat, dlon
  CHARACTER(LEN=1), INTENT(IN) :: cgrddef

  INTEGER :: n
  REAL    :: diff
  REAL    :: dlond, dlatd

  dlond=dlon
  dlatd=dlat
  IF (cgrddef .EQ. 'S') THEN
    DO n=1,np
      diff=glon(n)-lon0
      IF (diff <    0.) diff=diff+360.
      IF (diff >= 360.) diff=diff-360.
      lli(n) = diff/dlond+1.
      llj(n) = (glat(n)-lat0)/dlatd+1.
    END DO

  ELSE IF (cgrddef .EQ. 'N') THEN
    DO n=1,np
      diff=glon(n)-lon0
      IF (diff <    0.) diff=diff+360.
      IF (diff >= 360.) diff=diff-360.
      lli(n) = diff/dlon+1.
      llj(n) = (lat0-glat(n))/dlat+1.
    END DO

  ELSE
    print*, 'you must specify whether the standard  &
           & lat is Southern or Northern boundary'
  END IF

  RETURN
END SUBROUTINE latlon_2_llij


FUNCTION bilinear_interp(i,j,imax,jmax,array_2d) RESULT (zo)

  IMPLICIT NONE
  INTEGER, INTENT(IN) :: i,j,imax,jmax
  REAL,    INTENT(IN) :: array_2d(imax,jmax)
  REAL                :: zo

  REAL ::  z1,z2,z3,z4
  REAL ::  fraci,fracj

  fraci = 0.5
  fracj = 0.5

  z1 = array_2d(i  , j  )
  z2 = array_2d(i-1, j  )
  z3 = array_2d(i-1, j-1)
  z4 = array_2d(i  , j-1)

  zo = Z1 + (Z2-Z1)*fraci + (Z4-Z1)*fracj - (Z2+Z4-Z3-Z1)*fraci*fracj

END FUNCTION bilinear_interp