!
!##################################################################
!##################################################################
!######                                                      ######
!######             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,29
                            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 == 3) THEN                  ! HDF 4 format

    CALL hdfopen(hisfile(1:lenfil),1,nchr)

    CALL hdfrdi(nchr,"nx",nx,ireturn)
    CALL hdfrdi(nchr,"ny",ny,ireturn)
    CALL hdfrdi(nchr,"nz",nz,ireturn)
    CALL hdfrdi(nchr,"nzsoil",nzsoil,ireturn)
    CALL hdfrdi(nchr,"nstyp", nstyps,ireturn)

    CALL hdfrdi(nchr,"month", month, ireturn)
    CALL hdfrdi(nchr,"day",   day,   ireturn)
    CALL hdfrdi(nchr,"year",  year,  ireturn)
    CALL hdfrdi(nchr,"hour",  hour,  ireturn)
    CALL hdfrdi(nchr,"minute",minute,ireturn)
    CALL hdfrdi(nchr,"second",second,ireturn)
  
    CALL hdfrdi(nchr,"mapproj",mapproj,ireturn)
    CALL hdfrdr(nchr,"trulat1",trulat1,ireturn)
    CALL hdfrdr(nchr,"trulat2",trulat2,ireturn)
    CALL hdfrdr(nchr,"trulon", trulon, ireturn)
    CALL hdfrdr(nchr,"sclfct", sclfct, ireturn)
    CALL hdfrdr(nchr,"ctrlat", ctrlat, ireturn)
    CALL hdfrdr(nchr,"ctrlon", ctrlon, ireturn)
  
    CALL hdfrdr(nchr,"time",time,ireturn)
  
    CALL hdfrdr(nchr,"dx",dx,ireturn)
    CALL hdfrdr(nchr,"dy",dy,ireturn)
  
    CALL hdfclose(nchr,ireturn)

  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,         &
                     rdummy,rdummy,rdummy,rdummy,rdummy,                &
                     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
                   grid_id,parent_id,i_parent_start,j_parent_start,     &
                   i_parent_end,j_parent_end,parent_grid_ratio,         &
                   nx,ny,dx,dy,                                         &
                   mapproj,trulat1,trulat2,trulon,ctrlat_moad,          &
                   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)  :: grid_id, parent_id
  INTEGER, INTENT(IN)  :: i_parent_start,j_parent_start
  INTEGER, INTENT(IN)  :: i_parent_end, j_parent_end
  INTEGER, INTENT(IN)  :: parent_grid_ratio
  INTEGER, INTENT(IN)  :: nx,ny
  REAL,    INTENT(IN)  :: dx,dy
  INTEGER, INTENT(IN)  :: mapproj
  REAL,    INTENT(IN)  :: trulat1,trulat2,trulon
  REAL,    INTENT(IN)  :: ctrlat_moad
  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',       grid_id,   istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'PARENT_ID',     parent_id, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'I_PARENT_START',i_parent_start, istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'J_PARENT_START',j_parent_start, istatus)

  CALL put_dom_ti_integer(nfid,io_form, 'I_PARENT_END',  i_parent_end,istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'J_PARENT_END',  i_parent_end,istatus)
  CALL put_dom_ti_integer(nfid,io_form, 'PARENT_GRID_RATIO',parent_grid_ratio,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_moad,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*256 :: path_soiltemp_1deg
  INTEGER       :: istatus

  CHARACTER(LEN=256) :: 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