c
cdis    Forecast Systems Laboratory
cdis    NOAA/OAR/ERL/FSL
cdis    325 Broadway
cdis    Boulder, CO     80303
cdis
cdis    Forecast Research Division
cdis    Local Analysis and Prediction Branch
cdis    LAPS   
cdis
cdis    This software and its documentation are in the public domain and
cdis    are furnished "as is."  The United States government, its
cdis    instrumentalities, officers, employees, and agents make no
cdis    warranty, express or implied, as to the usefulness of the software
cdis    and documentation for any purpose.  They assume no responsibility
cdis    (1) for the use of the software and documentation; or (2) to provide
cdis     technical support to users.
cdis
cdis    Permission to use, copy, modify, and distribute this software is
cdis    hereby granted, provided that the entire disclaimer notice appears
cdis    in all copies.  All modifications to this software must be clearly
cdis    documented, and are solely the responsibility of the agent making
cdis    the modifications.  If significant modifications or enhancements
cdis    are made to this software, the FSL Software Policy Manager
cdis    (softwaremgr@fsl.noaa.gov) should be notified.
cdis

C
C     ******************************************************************
C

      SUBROUTINE SFCOPQR(NO,MOF,NP,NIQ,NJQ,N2,N3,lcat 1,14
     +          ,XT,YT,RLAT,WLON1,ERAD,RWOFF,RSOFF
     +          ,DELTALLO,DELTAXP,DELTAYP,DELTAXQ,DELTAYQ
     +          ,IBLKSIZO,ISBEGO,IWBEGO,DATR,DATS,DATLN,DATLT
     +          ,OFN,WVLN,SILWT,dem_data,maxdatacat,istat_files)

c JS: removed dato array from subroutine argument list
c JS: added RWOFF/RSOFF - West and South offset of tile data

      real,  allocatable ::  dato(:,:,:,:)    !dato(no,no,mof,lcat)

      real,  allocatable ::  DATP(:,:,:)
      real,  allocatable ::  DATQ(:,:)
      real,  allocatable ::  DATQS(:,:,:)
      real,  allocatable ::  DATSM(:,:)
      real,  allocatable ::  DATSMX(:,:)
      real,  allocatable ::  DATSLN(:,:)
      real,  allocatable ::  DATSLT(:,:)

      real,  intent(inout) ::  DATLN(N2,N3)
      real,  intent(out)   ::  DATLT(N2,N3)
      real,  intent(out)   ::  DATR(N2,N3)
      real,  intent(out)   ::  DATS(N2,N3,maxdatacat)

      real ISO(MOF),IWO(MOF),XT(N2),YT(N3),rlat,wlon1,
     +     erad,deltallo,deltaxp,deltayp,deltaxq,deltayq,
     +     wvln,silwt,xq,yq,xp,yp,xcentr,ycentr,glatp,               ! pla,plo,
     +     glonp,rio,rjo,wio2,wio1,wjo2,wjo1,xq1,yq1,
     +     rwoff,rsoff

      real r_missing_data
      real xr,yr,rval,sh,sha,rh,rha,rhn,rht,shn,sht
      real shln,shlt,rhln,rhlt
      real delta_ln(np,np),delta_lt(np,np)

c     real xpmn,xpmx,ypmn,ypmx
      real xp1,xp2,yp1,yp2
      real xpcentr,ypcentr

      real  pctcat(maxdatacat)

      integer lp
      integer ixr,iyr
      integer lent

      CHARACTER*180 OFN
      CHARACTER*180 TITLE3,TITLE3_last_read,TITLE3_last_inquire
      CHARACTER*3   TITLE1
      CHARACTER*4   TITLE2
      CHARACTER*10  cdatatype

      LOGICAL L1,L2,dem_data,l_string_contains

      data icnt/0/
      save icnt
C
      print *,'no,mof,np,niq,njq=',no,mof,np,niq,njq

      istat_files = 1

      NONO=NO*NO
      XCENTR=0.5*(XT(1)+XT(N2))
      YCENTR=0.5*(YT(1)+YT(N3))
      print *,xt(1),xt(n2),xcentr
      print *,'deltaxp=',deltaxp
      NOFR=0
      DO 11 IOF=1,MOF
         ISO(IOF)=0
         IWO(IOF)=0
  11  continue

      TITLE3_last_read    = '/dev/null'
      TITLE3_last_inquire = '/dev/null'

      lcat=1
      len=index(ofn,' ')
      if(ofn(len-1:len-1).eq.'V'.or.
     &   ofn(len-1:len-1).eq.'I')then
         icnt = 0
         cdatatype='landuse'
         if(ofn(len-1:len-1).eq.'I')cdatatype='islope'
      elseif(ofn(len-1:len-1).eq.'O')then
         icnt = 0
         cdatatype='soiltype'
      elseif(ofn(len-1:len-1).eq.'U' .or.
     &       ofn(len-1:len-1).eq.'H')then
         cdatatype='topography'
      endif

      print*,'SFCOPQR: cdatatype = ',cdatatype

!      call s_len(cdatatype,lent)
      lent = LEN_TRIM(cdatatype)

      allocate(dato(no,no,mof,lcat))

      allocate (DATP(NP,NP,lcat),
     &          DATQ(NIQ,NJQ),
     &          DATSM(NIQ,NJQ),
     &          DATSMX(NIQ,NJQ),
     &          DATSLN(NIQ,NJQ),
     &          DATSLT(NIQ,NJQ),
     &          DATQS(NIQ,NJQ,maxdatacat))

c      call get_r_missing_data(r_missing_data,istatus)
      r_missing_data = 1e+37
      istatus = 1

      if(istatus.ne.1)then
         print*,'failed to get r_missing_data'
         return
      endif

      DO 15 JQ=1,NJQ
         print *,'jq,njq,niq,nofr=',jq,njq,niq,nofr
         DO 16 IQ=1,NIQ

            XQ=(FLOAT(IQ)-0.5*FLOAT(NIQ+1))*DELTAXQ+XCENTR
            YQ=(FLOAT(JQ)-0.5*FLOAT(NJQ+1))*DELTAYQ+YCENTR

            xpmn=1.0e30
            ypmn=1.0e30
c           xpmx=-1.0e30
c           ypmx=-1.0e30

            DO 17 JP=1,NP
               DO 18 IP=1,NP

                  XP=XQ+(FLOAT(IP)-0.5*FLOAT(NP+1))*DELTAXP
                  YP=YQ+(FLOAT(JP)-0.5*FLOAT(NP+1))*DELTAYP

!                  call xy_to_latlon(XP,YP,erad,GLATP,GLONP) 
                  CALL xytoll(1,1,xp,yp,GLATP,GLONP)
!         print *, 'GLATP = ',glatp,' GLONP = ',glonp

                  glatp = max(-89.9999,min(89.9999,glatp - rsoff))
                  glonp = glonp - rwoff
                  if(glonp.ge.180.) glonp = glonp - 360.
                  if(glonp.le.-180.) glonp = glonp + 360.

c                 print *,'rlat,wlon1=',rlat,wlon1

                  ISOC=(INT((GLATP-FLOAT(ISBEGO))/FLOAT(IBLKSIZO)
     &          +200.)-200)*IBLKSIZO+ISBEGO
            IWOC=(INT((GLONP-FLOAT(IWBEGO))/FLOAT(IBLKSIZO)
     &          +400.)-400)*IBLKSIZO+IWBEGO

                  DO 19 IOFR=1,NOFR
                     JOFR=IOFR
                     IF(ISO(IOFR).EQ.ISOC.AND.IWO(IOFR).EQ.IWOC)GO TO 10
 19                 continue
                  ISOCPT=ABS(ISOC)/10
                  ISOCPO=ABS(ISOC)-ISOCPT*10
                  IWOCPH=ABS(IWOC)/100
                  IWOCPT=(ABS(IWOC)-IWOCPH*100)/10
                  IWOCPO=ABS(IWOC)-IWOCPH*100-IWOCPT*10
                  IF(ISOC.GE.0)THEN
                     WRITE(TITLE1,'(2I1,A1)')ISOCPT,ISOCPO,'N'
                  ELSE
                     WRITE(TITLE1,'(2I1,A1)')ISOCPT,ISOCPO,'S'
                  ENDIF

                  IF(IWOC.GE.0 
     1               .and. IWOC .ne. 180                    ! 1998 Steve Albers
     1                                      )THEN
                     WRITE(TITLE2,'(3I1,A1)')IWOCPH,IWOCPT,IWOCPO,'E'
                  ELSE
                     WRITE(TITLE2,'(3I1,A1)')IWOCPH,IWOCPT,IWOCPO,'W'
                  ENDIF

                  LB=LEN_TRIM(ofn)
                  TITLE3=OFN(1:LB)//TITLE1//TITLE2
                  LB=INDEX(TITLE3,' ')-1

!        print *, 'Title3 = ',title3
!        print *, 'Title3_last_inquire = ',title3_last_inquire
                  if(TITLE3 .ne. TITLE3_last_inquire)then
                     INQUIRE(FILE=TITLE3(1:LB),EXIST=L1,OPENED=L2)
                     TITLE3_last_inquire = TITLE3
                  endif

                  IF(.NOT.L1)THEN
                     iwrite = 0

                     if(icnt .le. 100)then ! Reduce the output
                         iwrite=1

                     elseif(icnt .le. 1000)then
                         if(icnt .eq. (icnt/100)*100)iwrite=1

                     elseif(icnt .le. 10000)then
                         if(icnt .eq. (icnt/1000)*1000)iwrite=1

                     elseif(icnt .le. 100000)then
                         if(icnt .eq. (icnt/10000)*10000)iwrite=1

                     else
                         if(icnt .eq. (icnt/100000)*100000)iwrite=1

                     endif

                     if(iwrite .eq. 1)then
                        if(l_string_contains(TITLE3(1:LB),
     1                                       'world_topo_30s',
     1                                       istatus)             )then       
                           PRINT*, ' ERROR: ',TITLE3(1:LB)
     1                            ,' DOES NOT EXIST ',icnt

                        elseif(l_string_contains(TITLE3(1:LB),
     1                                           'topo_30s',
     1                                       istatus)             )then       
                             PRINT*, ' topo_30s file ',TITLE3(1:LB)
     1                            ,' does not exist, using topo_10m '
     1                            ,icnt

                        else ! Generic warning message
                           PRINT*, ' WARNING: ',TITLE3(1:LB)
     1                            ,' DOES NOT EXIST ',icnt

                        endif

                     endif ! iwrite

                     icnt = icnt + 1

c initialize these arrays as they may have some garbage in them
c if we dont actually read in any data.
c
                     DATP(IP,JP,:) = 0.
                     DELTA_LN(IP,JP) = 0.
                     DELTA_LT(IP,JP) = 0.
                     istat_files = 0
                     GO TO 20

                  ENDIF

                  IF(NOFR.GE.MOF)THEN
                     DO 21 IOF=1,MOF
                        ISO(IOF)=0
                        IWO(IOF)=0
21                    continue
                     NOFR=0
                  ENDIF
                  NOFR=NOFR+1
                  JOFR=NOFR

!                 Read the tile
                  if(TITLE3 .ne. TITLE3_last_read)then
                    if( (ofn(len-1:len).eq.'U').and.(no.eq.1200).or.
     .                   no.eq.1201 )then
                         if(no.eq.1201)then
                            print*,'Reading ', title3(1:lb)
                            CALL READ_DEM(29,TITLE3(1:LB),no,no,4,4, ! topo_3s experimental
     .                              DATO(1,1,NOFR,1),istat)
                         else
                            CALL READ_DEM(29,TITLE3(1:LB),no,no,2,2, ! world topo_30s
     .                              DATO(1,1,NOFR,1),istat)
                         endif
                      dem_data=.true.
                    elseif( (ofn(len-1:len).eq.'O') )then      ! soiltype top and bot layer
                      CALL READ_DEM(29,TITLE3(1:LB),no,no,1,4,
     .                              DATO(1,1,NOFR,1),istat)
                      dem_data=.true.
                    elseif( (ofn(len-1:len).eq.'V') )then      ! world USGS 30s landuse
                      CALL READ_DEM(29,TITLE3(1:LB),no,no,1,4,
     .                              DATO(1,1,NOFR,1),istat)
                      dem_data=.true.
                    elseif((ofn(len-1:len).eq.'I'))then      ! only islope in this code section
                      CALL READ_DEM_G(29,TITLE3(1:LB),no,no,1,lcat
     .                     ,nofr, 1,4, DATO,istat)
                      dem_data=.true.
                    elseif( (ofn(len-1:len).eq.'T') )then      ! soiltemp - obsolete in this code
                      CALL READ_DEM(29,TITLE3(1:LB),no,no,2,2,
     .                              DATO(1,1,NOFR,1),istat)
                      dem_data=.true.
                    else                                       ! other
!                      CALL JCLGET(29,TITLE3(1:LB),'FORMATTED',0,istatus)      
             OPEN(29,STATUS='OLD',FILE=TITLE3(1:LB),FORM='FORMATTED')
                      CALL VFIREC(29,DATO(1,1,NOFR,1),NONO,'LIN')
                      if ((ofn(len-1:len).eq.'U').and.(no.eq.121)) then
                        dem_data=.false.                       ! topo_30s
                      endif
                    endif

                    if(istat.ne.0)then
                       print*,'Error returned: SFCOPQR: READ_DEM'
                       return
                    endif


                    TITLE3_last_read = TITLE3

c                   print *,'nofr,dato=',nofr,dato(1,1,nofr)
                    CLOSE(29)

                  else
                    write(6,*)' We have made the code more efficient'

                  endif ! Is this a new file we haven't read yet?

                  ISO(NOFR)=ISOC
                  IWO(NOFR)=IWOC
10		  continue

                  RIO=(GLONP-FLOAT(IWOC))/DELTALLO+1.
                  RJO=(GLATP-FLOAT(ISOC))/DELTALLO+1.

!                 Prevent Bounds Error (Steve Albers)
                  if(RIO .lt. 1.0)then
                      if(RIO .gt. 0.98)then
                          write(6,*)' Reset RIO for Machine Epsilon'      
                          RIO = 1.0
                      elseif(RIO .lt. 0.5)then
                          write(6,*)' ERROR: RIO out of bounds',RIO
                          stop
                      endif
                  endif

                  if(RJO .lt. 1.0)then
                      if(RJO .gt. 0.98)then
                          write(6,*)' Reset RJO for Machine Epsilon'      
                          write(6,*)JQ,IQ,
     1                          IP,JP,IO1,JO1,JOFR,RIO,RJO,GLATP,ISOC
                          RJO = 1.0
                      elseif(RJO .lt. 0.5)then
                          write(6,*)' ERROR: RJO out of bounds',RJO
                          write(6,*)JQ,IQ,
     1                          IP,JP,IO1,JO1,JOFR,RIO,RJO,GLATP,ISOC
                          stop
                      endif
                  endif

C Interp OK for continuous data such as topography

                  if(cdatatype.eq.'topography')then

                   IO1=INT(RIO)
                   JO1=INT(RJO)
                   IO2=IO1+1
                   JO2=JO1+1
                   WIO2=RIO-FLOAT(IO1)
                   WJO2=RJO-FLOAT(JO1)
                   WIO1=1.0-WIO2
                   WJO1=1.0-WJO2

                   do LP = 1,lcat

                   DATP(IP,JP,LP)=WIO1*(WJO1*DATO(IO1,JO1,JOFR,LP)
     +                                 +WJO2*DATO(IO1,JO2,JOFR,LP))
     +                           +WIO2*(WJO1*DATO(IO2,JO1,JOFR,LP)
     +                                 +WJO2*DATO(IO2,JO2,JOFR,LP))

!S & W-facing slopes > 0.
                   DELTA_LN(IP,JP)=
     .           ((DATO(IO2,JO1,JOFR,LP)-DATO(IO1,JO1,JOFR,LP))+
     .            (DATO(IO2,JO2,JOFR,LP)-DATO(IO1,JO2,JOFR,LP)))*.5

                   DELTA_LT(IP,JP)=
     .           ((DATO(IO1,JO2,JOFR,LP)-DATO(IO1,JO1,JOFR,LP))+
     .            (DATO(IO2,JO2,JOFR,LP)-DATO(IO2,JO1,JOFR,LP)))*.5

                   enddo !LP = 1,lcat

                  else

C Nearest grid point for landuse and soiltype

                   IO1=NINT(RIO)
                   JO1=NINT(RJO)
                   do LP = 1,lcat
                    DATP(IP,JP,LP)= DATO(IO1,JO1,JOFR,LP)
                   enddo

                  endif ! cdatatype eq topography.
                   
20               CONTINUE
18             continue ! IP
17           continue ! JP


!           print*,'xpmx/xpmn//ypmx/ypmn/ ',xpmx,xpmn,ypmx,ypmn

! Calculate average and silhouette terrain, then apply SILWT weight

            if(cdatatype(1:lent).eq.'topography')then

             SHA=0.
             RHA=0.
             RHLN=0.
             RHLT=0.
             shmax=0.

             DO 22 JP=1,NP
               SH=0.
               RH=0.
               RHN=0.
               RHT=0.
               DO 23 IP=1,NP
!                 Test for missing - then go to 16?
                  SH=max(SH,DATP(IP,JP,1)) 
                  RH=RH+DATP(IP,JP,1)
                  RHN=RHN+DELTA_LN(IP,JP)
                  RHT=RHT+DELTA_LT(IP,JP)
23             continue ! IP
               SHA=SHA+SH/(2.*FLOAT(NP))
               RHA=RHA+RH
               RHLN=RHLN+RHN
               RHLT=RHLT+RHT
               SHMAX=max(SHMAX,SH)
22           continue ! JP
 
             RHA=RHA/FLOAT(NP*NP)
             RMS=0.0
             DO 24 IP=1,NP 
               SH=0.
               DO 25 JP=1,NP
                  SH=max(SH,DATP(IP,JP,1))
                  RMS=RMS+((DATP(IP,JP,1)-RHA)*(DATP(IP,JP,1)-RHA))
25             continue ! JP
               SHA=SHA+SH/(2.*FLOAT(NP))
24           continue ! IP

             DATQS(IQ,JQ,1)=SQRT(RMS/FLOAT(NP*NP))
             DATQ(IQ,JQ)=SHA*SILWT+RHA*(1.-SILWT)
             DATSM(IQ,JQ)=RHA                           !mean value of points used for IQ,JQ
             DATSMX(IQ,JQ)=SHMAX                        !max value from points used for IQ,JQ
             DATSLN(IQ,JQ)=RHLN/FLOAT(NP*NP)/DELTAXP
             DATSLT(IQ,JQ)=RHLT/FLOAT(NP*NP)/DELTAYP

c            print *,'datq=',datq(iq,jq)

            elseif(cdatatype(1:lent).eq.'islope'    .or.
     &             cdatatype(1:lent).eq.'landuse'   .or.
     &             cdatatype(1:lent).eq.'soiltype'    )then

             call compute_categories(cdatatype,np*np,DATP(1,1,1)
     &               ,maxdatacat,domcat,pctcat)
             datq(iq,jq)=domcat 
             datqs(iq,jq,:)=pctcat(:)

            elseif(cdatatype(1:lent).eq.'greenfrac'   )then

c dominant greenness fraction for each month

             do lp=1,lcat
              call compute_categories(cdatatype,np*np,DATP(1,1,lp)
     &                               ,1,domcat,pctcat)
              datqs(iq,jq,lp)=domcat
             enddo

            endif

16       continue ! IQ
15    continue ! JQ

      print *,'after 15'
 
      XQ1=(1.-0.5*FLOAT(NIQ+1))*DELTAXQ+XCENTR
      YQ1=(1.-0.5*FLOAT(NJQ+1))*DELTAYQ+YCENTR

      if(cdatatype(1:lent).eq.'topography')then

        print*
        print*,'Before GDTOST2'
        print*,'--------------'
        print*,'datq(1,1)/(niq,njq)= ',datq(1,1),datq(niq,njq)
        print*,'datqs(1,1,1)/(niq,njq)= ',datqs(1,1,1),datqs(niq,njq,1)
        print*,'datsln(1,1)/(niq,njq)= ',datsln(1,1),datsln(niq,njq)
        print*,'datslt(1,1)/(niq,njq)= ',datslt(1,1),datslt(niq,njq)
        print*,'Mean/Max topo at IQ,JQ (1,1)/(niq,njq): '
     +,datsm(1,1),datsmx(1,1),datsm(niq,njq),datsmx(niq,njq)

        DO 28 JR=1,N3
         DO 29 IR=1,N2
           XR=(XT(IR)-XQ1)/DELTAXQ+1.
           YR=(YT(JR)-YQ1)/DELTAYQ+1.

           CALL GDTOST2(DATQ,NIQ,NJQ,XR,YR,RVAL)
           DATR(IR,JR)=max(0.,RVAL)
           if( DATR(IR,JR).gt.30000. )then
               print*,'Warning: value out of bounds'
           endif    

           CALL GDTOST2(DATQS,NIQ,NJQ,XR,YR,RVAL)
           DATS(IR,JR,1)=max(0.,RVAL)
           CALL GDTOST2(DATSLN,NIQ,NJQ,XR,YR,RVAL)
           DATLN(IR,JR)=RVAL
           CALL GDTOST2(DATSLT,NIQ,NJQ,XR,YR,RVAL)
           DATLT(IR,JR)=RVAL

 29      CONTINUE
 28     CONTINUE

        print*,'After GDTOST2'
        print*,'-------------'
        print*,'datr(1,1)/(n2,n3)= ',datr(1,1),datr(N2,N3)
        print*,'dats(1,1,1)/(n2,n3)= ',dats(1,1,1),dats(n2,n3,1)
        print*,'datln(1,1)/(n2,n3)= ',datln(1,1),datln(n2,n3)
        print*,'datlt(1,1)/(n2,n3)= ',datlt(1,1),datlt(n2,n3)
 
      elseif(cdatatype(1:lent).eq.'landuse'.or.
     +       cdatatype(1:lent).eq.'islope' .or.
     +       cdatatype(1:lent).eq.'soiltype')then

        DO 38 JR=1,N3
         DO 39 IR=1,N2
            IXR=NINT((XT(IR)-XQ1)/DELTAXQ)+1.
            IYR=NINT((YT(JR)-YQ1)/DELTAYQ)+1.
            if(ixr.lt.1)ixr=1
            if(iyr.lt.1)iyr=1
            if(ixr.gt.n2)ixr=niq
            if(iyr.gt.n3)iyr=njq

            datr(ir,jr)=  datq(ixr,iyr)     !dominant category
            dats(ir,jr,:)=datqs(ixr,iyr,:)  !percent dist for ea category

 39      CONTINUE
 38     CONTINUE

      endif

      deallocate(dato)
      deallocate(DATP,
     &           DATQ,
     &           DATQS,
     &           DATSM, 
     &           DATSMX,
     &           DATSLN,
     &           DATSLT)

      RETURN
      END


      SUBROUTINE GDTOST2(A,IX,IY,STAX,STAY,STAVAL) 4,2
*  SUBROUTINE TO RETURN STATIONS BACK-INTERPOLATED VALUES(STAVAL)
*  FROM UNIFORM GRID POINTS USING OVERLAPPING-QUADRATICS.
*  GRIDDED VALUES OF INPUT ARRAY A DIMENSIONED A(IX,IY),WHERE
*  IX=GRID POINTS IN X, IY = GRID POINTS IN Y .  STATION
*  LOCATION GIVEN IN TERMS OF GRID RELATIVE STATION X (STAX)
*  AND STATION COLUMN.
*  VALUES GREATER THAN 1.0E30 INDICATE MISSING DATA.
*
      real A(IX,IY),R(4),SCR(4),stax,stay,staval
     +  ,fixm2,fiym2,yy,xx
      IY1=INT(STAY)-1
      IY2=IY1+3
      IX1=INT(STAX)-1
      IX2=IX1+3
      STAVAL=1E30
      FIYM2=FLOAT(IY1)-1
      FIXM2=FLOAT(IX1)-1
      II=0
      DO 100 I=IX1,IX2
      II=II+1
      IF(I.GE.1.AND.I.LE.IX) GO TO 101
      SCR(II)=1E30
      GO TO 100
101   JJ=0
      DO 111 J=IY1,IY2
      JJ=JJ+1
      IF(J.GE.1.AND.J.LE.IY) GO TO 112
      R(JJ)=1E30
      GO TO 111
112   R(JJ)=A(I,J)
111   CONTINUE
      YY=STAY-FIYM2
      CALL BINOM(1.,2.,3.,4.,R(1),R(2),R(3),R(4),YY,SCR(II))
100   CONTINUE
      XX=STAX-FIXM2
      CALL BINOM(1.,2.,3.,4.,SCR(1),SCR(2),SCR(3),SCR(4),XX,STAVAL)
      RETURN
      END
c
cc ------------------------------------------------------------------
c

      subroutine vfirec(iunit,a,n,type) 2,1
      character*1 vc
      character*(*) type
      common/vform/vc(0:63)
      character line*80, cs*1
      dimension a(*)

      if(vc(0).ne.'0') call vfinit

      ich0=ichar('0')
      ich9=ichar('9')
      ichcz=ichar('Z')
      ichlz=ichar('z')
      ichca=ichar('A')
      ichla=ichar('a')
      
      read(iunit,10)nn,nbits,bias,fact
 10   format(2i8,2e20.10)
      if(nn.ne.n) then
         print*,' Word count mismatch on vfirec record '
         print*,' Words on record - ',nn
         print*,' Words expected  - ',n
         stop 'vfirec'
      endif

      nvalline=(78*6)/nbits
      nchs=nbits/6
      do 20 i=1,n,nvalline
         read(iunit,'(a78)') line
         ic=0
         do 30 ii=i,i+nvalline-1
            isval=0
            if(ii.gt.n) go to 20
            do 40 iii=1,nchs
               ic=ic+1
               cs=line(ic:ic)
               ics=ichar(cs)
               if(ics.le.ich9)then
                  nc=ics-ich0
               elseif(ics.le.ichcz) then
                  nc=ics-ichca+10
               else
                  nc=ics-ichla+36
               endif
               isval=ior(ishft(nc,6*(nchs-iii)),isval)
 40         continue
            a(ii)=isval
 30      continue
 20   continue

      facti=1./fact
      if(type.eq.'LIN') then
         do 48 i=1,n
            a(i)=a(i)*facti-bias
 48      continue
      elseif(type.eq.'LOG') then
         scfct=2.**(nbits-1)
         do 55 i=1,n
            a(i)=sign(1.,a(i)-scfct)
     +           *(10.**(abs(20.*(a(i)/scfct-1.))-10.))
 55      continue
      endif

      return
      end
c
cc ------------------------------------------------------------------
c

      subroutine vfinit                                                   1
      character*1vc,vcscr(0:63)                                         
      common/vform/vc(0:63)                                             
      data vcscr/'0','1','2','3','4','5','6','7','8','9'                 
     +,'A','B','C','D','E','F','G','H','I','J'                          
     +,'K','L','M','N','O','P','Q','R','S','T'                          
     +,'U','V','W','X','Y','Z','a','b','c','d'                          
     +,'e','f','g','h','i','j','k','l','m','n'                          
     +,'o','p','q','r','s','t','u','v','w','x'                          
     +,'y','z','{','|'/                                                 
                                                                        
      do10n=0,63                                                        
      vc(n)=vcscr(n)                                                    
  10  continue                                                          
                                                                        
      return                                                            
      end
C +------------------------------------------------------------------+

      FUNCTION INTLSHFT(IWORD,NSHFT)
C
C       This function shifts IWORD to the left NSHFT bits in a
C         circular manner.
C
      INTLSHFT=ISHFT(IWORD,NSHFT)
      RETURN
      END
C +------------------------------------------------------------------+
c
c determine dominant category 1-05-01 JS
c


      subroutine compute_categories(ctype,nnp,data,nlcat,domcat 2
     +,pctcat)

      implicit none

      character*(*) ctype

      integer nnp
      integer igc
      integer i,j,k
      integer nlcat
      integer maxcat
      integer lcat(nlcat)
      real    pctcat(nlcat)
      real    data(nnp)
      real    domcat
      real    sum_g

c categorical data types
      if(ctype.eq.'landuse'   .or.
     +   ctype.eq.'soiltype'  .or.
     +   ctype.eq.'islope'  )then

         do k=1,nlcat
            lcat(k)=0
            pctcat(k)=0.
         enddo

         do i=1,nnp
         do k=1,nlcat
            if(nint(data(i)).eq.k)then
               lcat(k)=lcat(k)+1
            endif
         enddo
         enddo

         maxcat=-1
         do k=1,nlcat
            pctcat(k)=lcat(k)/float(nnp)
            if(lcat(k).gt.maxcat)then
               maxcat=lcat(k)
               domcat=float(k)
            endif
         enddo
         if(ctype.eq.'landuse')then
          if(pctcat(16).ge.0.5) then                            !!JBresch
	    domcat = 16                                         !!JBresch
          else if(domcat.eq.16.and.pctcat(16).lt.0.5)then       !!JBresch
            maxcat=-1
            do k=1,nlcat
               if(k.ne.16)then
                  if(lcat(k).gt.maxcat)then
                     maxcat=lcat(k)
                     domcat=float(k)
                  endif
               endif
            enddo
          endif
         endif

c quantitative data types
      elseif(ctype.eq.'greenfrac'.or.ctype.eq.'soiltemp')then

         sum_g=0.
         igc=0
         do i=1,nnp
          if(data(i).gt.0.0)then
             sum_g=sum_g+data(i)
             igc = igc+1
          endif
         enddo
         if(igc.gt.0)then
            domcat=sum_g/float(igc)
         else
            domcat=0.0
         endif

      endif

      return
      end


c ********************************************************************


	subroutine read_dem(unit_no,unit_name,nn1,nn2,i1,i2 9,1
     &,data,istat)

	implicit none

	integer countx,county,unit_no,nn1,nn2

        character  cdata(nn1,nn2)*2
        integer,   allocatable :: idata(:,:)
	real       data(nn1,nn2)
	integer len, lend, i1, i2, ia, istat
        real multiplier
c       logical l1,l2
	character*(*) unit_name
        character*1   ctiletype

C	open(unit_no,file=unit_name,status='old',access='direct',
C	. recl=nn2*nn1*2)
C	inquire(unit_no,exist=l1,opened=l2)
C	read(unit_no,rec=1) idata

!	call s_len(unit_name,len)
        len = LEN_TRIM(unit_name)

        call get_directory_length(unit_name,lend)
        ctiletype=unit_name(lend+1:lend+1)

        if(.not.allocated(idata))then
           allocate (idata(nn1,nn2),stat=istat)
           if(istat.ne.0)then
              print*,'unable to allocate idata array: read_dem'
              print*,'nn1/nn2/istat: ',nn1,nn2,istat
              return
           endif
        endif


        multiplier=1.0
	if(ctiletype.eq.'T'.or.ctiletype.eq.'U')then
           if(nn1.eq.1201)then
              open(unit_no,file=unit_name,status='old',
     .form='unformatted')
              read(unit_no)data
              close(unit_no)
           else
              call read_binary_field(cdata,i1,i2,nn1*nn2,unit_name,len)

              do county=1,nn2
              do countx=1,nn1
               idata(countx,county) = ia (cdata(countx,county),2,0)
              enddo
              enddo
              if(ctiletype.eq.'T')multiplier=.01  !(for T data these are temps * 100)
           endif
        else
           call read_binary_field(idata,i1,i2,nn1*nn2,unit_name,len)
        endif

        if(nn1.le.1200)then
	do county=1,nn2
	do countx=1,nn1
	 if(idata(countx,county).eq.-9999) idata(countx,county)=0
	  data(countx,county)=float(idata(countx,nn2-county+1))
     &*multiplier
c SG97 initial data (DEM format) starts in the lower-left corner;
c SG97 this format is wrapped around to have upper-left corner as its start.
c
c JS00 some machines do not account for signed integers
	   if(data(countx,county).ge.15535.0)
     &data(countx,county)=data(countx,county)-65535

	enddo
	enddo
        endif
 
        if(allocated (idata))deallocate(idata)

ccc	 close(unit_no)
	return
	end

c ********************************************************************


        subroutine read_dem_g(unit_no,unit_name,nn1,nn2,nn3,nn4 2,1
     &,nofr,i1,i2,data,istat)

        implicit none
        integer  countx,county,countz
        integer  unit_no,nn1,nn2,nn3,nn4,nofr
        integer  len, lend, i1, i2, i
        integer  istat

        real     data(nn1,nn2,nn3,nn4)
        integer, allocatable ::  idata(:,:,:)

c       logical  l1,l2

        character*(*) unit_name
        character*1   ctype

C       open(unit_no,file=unit_name,status='old',access='direct',
C       . recl=nn2*nn1*2)
C       inquire(unit_no,exist=l1,opened=l2)
C       read(unit_no,rec=1) idata

        if(.not.allocated(idata))then
           print*,'allocate idata in read_dem_g'
           allocate (idata(nn4,nn1,nn2),stat=istat)
           if(istat.ne.0)then
              print*,'unable to allocate idata array: read_dem_g'
              print*,'nn1/nn2/nn4/istat: ',nn1,nn2,nn4,istat
              return
           endif
        endif

!        call s_len(unit_name,len)
        len = LEN_TRIM(unit_name)

        call get_directory_length(unit_name,lend)
        ctype=unit_name(lend+1:lend+1)

        print*,'read_dem_g: tile type = ',ctype

        call read_binary_field(idata,i1,i2,nn1*nn2*nn4,unit_name,len)

c       if(nn1.ne.1250 .and. nn2.ne.1250)then
        if(ctype.ne.'A' .and. 
     &     ctype.ne.'G' .and.
     &     ctype.ne.'I' .and.
     &     ctype.ne.'M')then

           do county=1,nn2
           do countx=1,nn1
           do countz=1,nn4

              if(idata(countz,countx,county).eq.-9999)
     &idata(countz,countx,county)=0

              data(countx,county,nofr,countz)=
     &float(idata(countz,countx,nn2-county+1))

c SG97 initial data (DEM format) starts in the lower-left corner;
c SG97 this format is wrapped around to have upper-left corner as its start.


           enddo
           enddo
           enddo

        else   !new greenfrac data starts at 90S

           do county=1,nn2
           do countx=1,nn1
           do countz=1,nn4

              data(countx,county,nofr,countz)=
     &float(idata(countz,countx,county))

           enddo
           enddo
           enddo

        endif

c we'll resurrect the actual categories later
c but for now we want categories 1-9 for
c terrain slope index.
        if(ctype == 'I')then
           do county=1,nn2
           do countx=1,nn1
              if(data(countx,county,1,1).eq.13)then
                 data(countx,county,1,1)=8
              elseif(data(countx,county,1,1).eq.0)then
                 data(countx,county,1,1)=9
              endif
           enddo
           enddo
c          where(data .eq. 13)data = 8
c          where(data .eq. 0)data = 9
        endif

        if(allocated(idata))deallocate(idata)

ccc      close(unit_no)
        return
        end
C
C********************************************************************
C

        subroutine get_directory_length(c_fname,lenf) 3

cdoc    This routine takes as input a full path filename and returns an
cdoc    index that points at the end of the directory portion of the pathname.
C       Simple-minded algorithm just searches backwards for the first
C       occurance of a `/' (for UNIX) or a `]' (for VMS).
C
C       Input/Output:
C
C       Name            Type    I/O     Description
C       ----            ---     --      -----------
C       c_fnames        char    I       file name.
C       lenf            I       O       index to end of directory
C
C********************************************************************
C
        character c_fname*(*)
        integer*4 lenf

        integer*4 i, strlen
C
C****************************
C
        strlen = len(c_fname)

        i = strlen
        do while (i .gt. 0)
        if( (c_fname(i:i) .ne. ']')
     1.and. (c_fname(i:i) .ne. '/') )then
           i = i-1
        else
           goto 100
        endif
        enddo

100     lenf = i

        return
        end

C*****************************************************************


        function l_string_contains(string,substring,istatus)
 
cdoc    Returns boolean on whether 'string' contains 'substring'
cdoc    The 'string' and 'substring' should be free of blanks.
 
        logical l_string_contains
 
        character*(*) string
        character*(*) substring
 
        l_string_contains = .false.
 
!        call s_len(string,len1)
!        call s_len(substring,len2)
        len1 = LEN_TRIM(string)
        len2 = LEN_TRIM(substring)

        if(len1 .ge. len2)then
            i_search_end = len1 - len2 + 1
 
            do i = 1,i_search_end
                if(string(i:i+len2-1) .eq. substring(1:len2))then
                    l_string_contains = .true.
                endif
            enddo ! i
 
            istatus = 1
            return
 
        else
            istatus = 0
            return
 
        endif
 
        end

c
c===============================================================================
c

      subroutine binom(x1,x2,x3,x4,y1,y2,y3,y4,xxx,yyy) 2
c
!      include 'bgdata.inc'
!      yyy=missingflag
      yyy = 1.0e37

      if (x2 .gt. 1.e19 .or. x3 .gt. 1.e19 .or.
     .    y2 .gt. 1.e19 .or. y3 .gt. 1.e19) return
c
      wt1=(xxx-x3)/(x2-x3)
      wt2=1.0-wt1
c
      if (y4 .lt. 1.e19 .and. x4 .lt. 1.e19) then
c        yz22=(xxx-x3)*(xxx-x4)/((x2-x3)*(x2-x4))
         yz22=wt1*(xxx-x4)/(x2-x4)
c        yz23=(xxx-x2)*(xxx-x4)/((x3-x2)*(x3-x4))
         yz23=wt2*(xxx-x4)/(x3-x4)
         yz24=(xxx-x2)*(xxx-x3)/((x4-x2)*(x4-x3))
      else
         yz22=wt1
         yz23=wt2
         yz24=0.0
      endif
c
      if (y1 .lt. 1.e19 .and. x1 .lt. 1.e19) then
         yz11=(xxx-x2)*(xxx-x3)/((x1-x2)*(x1-x3))
c        yz12=(xxx-x1)*(xxx-x3)/((x2-x1)*(x2-x3))
         yz12=wt1*(xxx-x1)/(x2-x1)
c        yz13=(xxx-x1)*(xxx-x2)/((x3-x1)*(x3-x2))
         yz13=wt2*(xxx-x1)/(x3-x1)
      else
         yz11=0.0
         yz12=wt1
         yz13=wt2
      endif
c
      if (yz11 .eq. 0. .and. yz24 .eq. 0.) then
         yyy=wt1*y2+wt2*y3
      else
         yyy=wt1*(yz11*y1+yz12*y2+yz13*y3)+wt2*(yz22*y2+yz23*y3+yz24*y4)
      endif
c
      return
      end

!----------------------------------------------------------------------

        FUNCTION IA(CHR,N,ISPVAL)
!                                                              
!  PURPOSE: TO CONVERT A N-BYTES CHARACTER (CHR) TO INTEGER IA. 
!        ** THE INTEGER DATA FILE IS SAVED AS A N-BYTE CHARACTER
!           DATA FILE. THIS FUNCTION IS USED TO RECOVER THE    
!           CHARACTER DATA TO THE INTEGER DATA.               
!                                                            
!  N      --- THE NUMBER OF BYTES IN CHR                    
!  ISPVAL --- DEFAULT VALUE FOR THE NEGATIVE INTEGER.      
!                                                       
        CHARACTER*(*) :: CHR
        integer  N, II1, II2, JJ, ISN, M, NBIT, MSHFT, IA2, ispval
        INTEGER  BIT_1, BIT_2
!                                                    
        BIT_1 = O'200'     ! BINARY '10000000'        
        BIT_2 = O'377'     ! BINARY '11111111'       
        IA    = 0
!                                                
        II1 = ICHAR(CHR(1:1))
        if(II1 < 0) II1=II1+256
 
! .. GET THE SIGN -- ISN=0 POSITIVE, ISN=1 NEGATIVE:
        JJ  = IAND(II1,BIT_1)
        ISN = ISHFT(JJ,-7)
!                                                
! .. FOR NEGATIVE NUMBER:
!    BECAUSE THE NEGATIVE INTEGERS ARE REPRESENTED BY THE SUPPLEMENTARY
!    BINARY CODE INSIDE MACHINE.
!                              
        IF (ISN.EQ.1) THEN
          DO M = N+1,4
           NBIT = (M-1)*8
           JJ = ISHFT(BIT_2,NBIT)
           IA = IEOR(JJ,IA)
          END DO
        ENDIF
!                              
!   .. GET THE BYTE FROM CHR: 
        DO M = 1,N
         II2 = ICHAR(CHR(M:M))
         if(II2 < 0) II2=II2+256
         MSHFT = (N-M)*8
         IA2   = ISHFT(II2,MSHFT)
!   .. THE ABS(INTEGER):          
         IA = IEOR(IA,IA2)
        END DO
!                              
        IF (IA.LT.0) IA = ISPVAL
!                            
        RETURN
        END

! See WRFSI src/grid/proc_geodat.f
!

      subroutine proc_geodat(nx_dom,ny_dom,ncat 4,10
     1,path_to_tile_data,dom_lats_in,dom_lons_in,lmask_out
     1,geodat,istatus)
!    1,cat_pct)
!
! J. Smart (NOAA/FSL) : 2002            original version
! T. Hume/T. Simmers Meteorological Service of New Zealand
!                     : 2002
!                    Corrected problems with crossing the dateline
!                    and constrained albedo to one tile.
! J. Smart (NOAA/FSL) : 2003
!                    Further refined processing of tiles to accomodate
!                    dateline, Greenwich mean, and Poles. Added smoothing
!                    of temp field (subroutine one_two_one).

!      use horiz_interp

      implicit none 
      integer maxtiles 
      integer nx_dom 
      integer ny_dom
      integer ncat
      integer ntn,nt
      integer bgmodel
      integer itilesize_d
      integer lentd,lenp,lenf
      integer iblksizo
      integer isbego,iwbego
      integer no
      integer icurNS,icurEW
      integer itile
      integer itilex
      integer itiley
      integer,allocatable:: itile_lat(:)
      integer,allocatable:: itile_lon(:)
      integer itilelon
      integer it,jt
      integer is,js
      integer ie,je
      integer itx,ity
      integer i,j,k,ii,jj
      integer ix,iy
      integer icnta
      integer tile_n_lat
      integer tile_s_lat
      integer tile_w_lon
      integer tile_e_lon
      integer istatus
      integer istat

      integer nx_tile,ny_tile
      integer dom_i,dom_j
      integer point_value
      integer ilon,ilat
      integer method

      real    dom_lats_in(nx_dom,ny_dom)
      real    dom_lons_in(nx_dom,ny_dom)
      real    grx(nx_dom,ny_dom)
      real    gry(nx_dom,ny_dom)

!Define Array to keep count of number of raw tile data points found for each
!model grid point

!     real    cat_pct(nx_dom,ny_dom,ncat)
!     integer, allocatable :: num_raw_points_total (:,:)
!     integer, allocatable :: num_raw_points_cat(:,:,:)

      real,    allocatable :: raw_data(:,:,:)
      real,    allocatable :: data_proc(:,:,:)
      real,    allocatable :: lmask_src(:,:)
      real,    allocatable,   dimension(:,:)::dom_lats,dom_lons

      real    geodat(nx_dom,ny_dom,ncat)
      real    lmask_out(nx_dom,ny_dom)
      real    amean(ncat)
      real    asum(ncat)

      real    dlat_tile
      real    dlon_tile
      real    sw(2),ne(2)
      real    deltallo
      real    min_lat
      real    max_lat
      real    min_lon
      real    max_lon
      real    minlat
      real    maxlat
      real    minlon
      real    maxlon
      real    rwoff,rsoff
      real    rlondif
      real    offset
      real    ri,rj
      real    rmult
      real    min_val,max_val,def_val,val_mask
      real    r_missing_data
 
      logical  dem_data
      logical  make_srcmask
      logical  lexist,lopen

      character*(*) path_to_tile_data
      character*255 title
      character*255 cfname
      character(len=8),allocatable:: ctile_name_list(:)
      character*8   ctilename
      character*1   curNS,curEW
      character*1   ctiletype

      character*1   cgrddef
      integer nxst,nyst,nz
      real    lat0,lon0,dlat,dlon
!      common /llgrid/nxst,nyst,nz,lat0,lon0,dlat,dlon,cgrddef

c original create from Brent Shaw pseudocode

      print*,'Start proc_geodat'

      if(.not. allocated(dom_lats))then
          allocate(dom_lats(nx_dom,ny_dom),dom_lons(nx_dom,ny_dom))
      endif
      dom_lats=dom_lats_in
      dom_lons=dom_lons_in

! TH: 8 Aug 2002 Now we may need to adjust the longitude values in 
! dom_lons so that they are always monotonically increasing, even if 
! we have the bad fortune to cross the date line.
      DO jj=1,ny_dom-1
         DO ii=1,nx_dom
            IF ((dom_lons(ii,jj+1) - dom_lons(ii,jj)) < -180.) THEN
               dom_lons(ii,jj+1) = dom_lons(ii,jj+1) + 360.
            ELSE IF ((dom_lons(ii,jj+1) - dom_lons(ii,jj)) > 180.) THEN
               dom_lons(ii,jj+1) = dom_lons(ii,jj+1) - 360.
            END IF
         END DO
      END DO
! TH: 8 Aug 2002 We also have to cope with spastic grids that have
! "horizontal" date lines (where we might cross the date line by
! moving up and down the grid rather than left and right).
      DO jj=1,ny_dom
         DO ii=1,nx_dom-1
            IF ((dom_lons(ii+1,jj) - dom_lons(ii,jj)) < -180.) THEN
               dom_lons(ii+1,jj) = dom_lons(ii+1,jj) + 360.
            ELSE IF ((dom_lons(ii+1,jj) - dom_lons(ii,jj)) > 180.) THEN
               dom_lons(ii+1,jj) = dom_lons(ii+1,jj) - 360.
            END IF
         END DO
      END DO
! TH: 8 Aug 2002 Now we want to make sure our longitudes don't fall
! outside the range (-360,360).
      IF (MAXVAL(dom_lons(:,:)) > 360.) dom_lons(:,:) = dom_lons(:,:)
     1   - 360
      max_lat = MAXVAL(dom_lats)
      IF (MINVAL(dom_lons(:,:)) < -360.) dom_lons(:,:) = dom_lons(:,:)
     1   + 360

! nx_dom = number of East-West points in anal/model domain   I
! ny_dom = number of North-south points      "               I
! dom_lats(nx_dom,ny_dom)  ! Latitude array                  I
! dom_lons(nx_dom,ny_dom)  ! Longitude array                 I

!c      call s_len(path_to_tile_data,lenp)
      lenp = LEN_TRIM(path_to_tile_data)

      ctiletype=path_to_tile_data(lenp:lenp)
      if(ctiletype.eq.'T'.or.
     1   ctiletype.eq.'A'.or.
     1   ctiletype.eq.'G'.or.
     1   ctiletype.eq.'M' )then
         print*,'tile type to process = ',ctiletype
      else
         print*,'Unknown tile type in proc_geodat_tiles'
         print*,'path_to_tile_data: ',path_to_tile_data(1:lenp)
         stop
      endif

      bgmodel=6

      TITLE=path_to_tile_data(1:lenp)//'HEADER'
      lentd=INDEX(TITLE,' ')-1
!c     CALL JCLGET(29,TITLE(1:lentd),'FORMATTED',1,istatus)
      OPEN(29,FILE=title(1:lentd),FORM='FORMATTED',STATUS='old')

      if(istatus .ne. 1)then
         write(6,*)'Warning: proc_geodat_tiles opening HEADER: check'
     1            ,'geog paths and HEADER file'
         return
      endif

      READ(29,*)IBLKSIZO,NO,ISBEGO,IWBEGO,RWOFF,RSOFF
      print *,'title=',title(1:lentd)
      print *,'RWOFF,RSOFF = ',RWOFF,RSOFF
      print *,'isbego,iwbego=',isbego,iwbego
      print *,'iblksizo,no=',iblksizo,no
      CLOSE(29)

      if(ctiletype.eq.'T'.and.iblksizo.eq.10)then
       print*
       print*,'Error: ****************************************'
       print*,'Error: ********** TERMINATING *****************'
       print*,'Error: Old Soil Temp database!!!'
       print*,'Error: You need to update these'
       print*,'Error: data: ',TRIM(path_to_tile_data)
       print*,'Error: by downloading new soil temp data'
       print*,'Error: ********** TERMINATING *****************'
       print*,'Error: ****************************************'
       print*
      endif

      maxtiles=(360/iblksizo)*(180/iblksizo)
      print*,'Maxtiles = ',maxtiles

      if(NO .GT. 0)then
         DELTALLO=FLOAT(IBLKSIZO)/FLOAT(NO)
      else
         print *,'ERROR:  NO <= 0 ... '
         stop
      endif

      itilesize_d = iblksizo

! Define number of points in a raw tile and what the lat/lon increment
! between the points in a tile are

      nx_tile=no
      ny_tile=no
      dlat_tile=deltallo
      dlon_tile=dlat_tile

! ncat ! Number of categories (1 for topo, 24 for veg, etc.)
!Define Array to keep count of number of raw tile data points found for each
!model grid point

! Find min/max atitude and longitude so we can compute which tiles to 
! read

      minlat = MINVAL(dom_lats)
      maxlat = MAXVAL(dom_lats)
      minlon = MINVAL(dom_lons)
      maxlon = MAXVAL(dom_lons)

! no offsets needed here since these are the tiles, not the points
! in the tiles. However, since domains may need data from tiles with
! offset considered, add it in.
      min_lat = max(-89.9999, min(89.9999, minlat - abs(rsoff)))
      max_lat = max(-89.9999, min(89.9999, maxlat + abs(rsoff)))
      min_lon = max(-359.9999,min(359.9999,minlon - abs(rwoff)))
      max_lon = max(-359.9999,min(359.9999,maxlon + abs(rwoff)))

c     if(ctiletype .eq. 'G'.or.ctiletype.eq.'A')then
c        if(min_lon.lt.-180)min_lon=360.+min_lon
c     endif

      print*,'max/min lats: ',max_lat,min_lat
      print*,'max/min lons: ',max_lon,min_lon

      deallocate(dom_lats,dom_lons)

!  Compute a list of tiles needed to fulfill lat/lon range just computed

      print*,'allocate ctile_name_list lat/lon arrays'
      print*,'with maxtiles = ',maxtiles

      allocate (ctile_name_list(maxtiles))

      call get_tile_list(min_lat,max_lat,min_lon,max_lon
     1,maxtiles,isbego,iwbego,itilesize_d,ctiletype
     1,ntn,ctile_name_list,tile_w_lon,tile_e_lon
     1,tile_s_lat,tile_n_lat,istatus)

      if(istatus.ne.1)then
         print*,'ERROR:  returned from get_tile_list'
         return
      endif

      allocate (raw_data(nx_tile,ny_tile,ncat))
      allocate (itile_lat(ntn))
      allocate (itile_lon(ntn))

!     ALLOCATE(num_raw_points_total(nx_dom,ny_dom))
!     ALLOCATE(num_raw_points_cat(nx_dom,ny_dom,ncat))
!     num_raw_points_total(:,:)=0
!     num_raw_points_cat(:,:,:)=0

      do itile=1,ntn
         read(ctile_name_list(itile)(1:2),'(i2.2)')itile_lat(itile)
         read(ctile_name_list(itile)(4:6),'(i3.3)')itile_lon(itile)
         if(ctile_name_list(itile)(7:7).eq.'W')then
            if(itile_lon(itile).lt.180)then
               itile_lon(itile)=360-itile_lon(itile)
            endif
         endif
         if(ctile_name_list(itile)(3:3).eq.'S')then
            itile_lat(itile)=-1.0*itile_lat(itile)
         endif
      enddo

      print*,'S/N tile lat points = ',tile_s_lat,tile_n_lat
      print*,'W/E tile lon points = ',tile_w_lon,tile_e_lon

c determine the x/y size dimensions and allocate/initialize the super tile

      rlondif=abs(tile_e_lon-tile_w_lon)
      itx=nx_tile*nint((rlondif+itilesize_d)/float(itilesize_d))
      ity=ny_tile*nint((abs(tile_n_lat-tile_s_lat)+itilesize_d)
     ./float(itilesize_d))
      if(ctiletype.eq.'T' .or. ctiletype.eq.'M' .and.
     &itx.gt.360)itx=360
      if(ctiletype.eq.'G' .or. ctiletype.eq.'A' .and. 
     &itx.gt.2500)itx=2500
      print*,'allocate data_proc: nx/ny/ncat ',itx,ity,ncat
      allocate(data_proc(itx,ity,ncat))
!      call get_r_missing_data(r_missing_data,istatus)
      r_missing_data = 1.e+37
      data_proc = r_missing_data

c for the supertile lat-lon "grid" definition:
c the LL setup must consider the offsets since this
c is relevant to the actual data points within the tile.
      nxst=itx
      nyst=ity
      dlat=dlat_tile
      dlon=dlat
      lat0=tile_s_lat+rsoff
      if(tile_w_lon.gt.180)then
         lon0=tile_w_lon-360+rwoff 
      elseif(tile_w_lon.lt.-180)then
         lon0=360+tile_w_lon+rwoff
      else
         lon0=tile_w_lon+rwoff
      endif
      sw(1)=lat0
      sw(2)=lon0
      ne(1)=tile_n_lat+itilesize_d+rsoff
      ne(2)=tile_e_lon+itilesize_d+rwoff
      cgrddef='S'

      print*,'generate supertile for domain'
      print*,'number of small tiles needed= ',ntn
      print*

      DO itile = 1, ntn  !number of tiles needed
 
       ctilename=ctile_name_list(itile)
       cfname = path_to_tile_data(1:lenp)//ctilename(1:3)
       read(ctilename(4:6),'(i3.3)')icurEW
       read(ctilename(7:7),'(a1)')curEW
       IF (icurEW > 180)THEN    ! .and. icurEW < 360) THEN
          icurEW = 360 - icurEW
       ENDIF
       IF (icurEW == 180.and.curEW.ne.'W') THEN
          curEW = 'W' 
       END IF 

       write(cfname(lenp+4:lenp+6),'(i3.3)')icurEW
       write(cfname(lenp+7:lenp+7),'(a1)')curEW

!       call s_len(cfname,lenf)
       lenf = LEN_TRIM(cfname)

       print*,'processing tile: ',cfname(1:lenf)

       inquire(file=cfname,exist=lexist,opened=lopen)
       if(.not.lexist)then
          print*,'Error: file does not exist: ',cfname(1:lenp)
          goto 1000
       endif
       if(lopen)then
          print*,'Error: file already open: ',cfname(1:lenp)
          goto 1000
       endif


! Open the tile and read the points
       if( (ctiletype.eq.'U').and.(no.eq.1200) )then
           CALL READ_DEM(29,cfname,no,no,2,2,raw_data,istat) ! world topo_30s
           dem_data=.true.
       elseif( ctiletype.eq.'O' )then      ! soiltype top and bot layer
           CALL READ_DEM(29,cfname,no,no,1,4,raw_data,istat)
           dem_data=.true.
       elseif( ctiletype.eq.'V' )then      ! world USGS 30s landuse
           CALL READ_DEM(29,cfname,no,no,1,4,raw_data,istat)
           dem_data=.true.
       elseif( (ctiletype.eq.'G')
     1     .or.(ctiletype.eq.'A')
     1     .or.(ctiletype.eq.'M') )then      ! greenfrac/albedo/maxsnowalb
           CALL READ_DEM_G(29,cfname,no,no,1,ncat,1,1,4,raw_data,istat)
           dem_data=.true.
       elseif( ctiletype.eq.'T')then ! .or. ctiletype.eq.'M')then      ! soiltemp
           CALL READ_DEM(29,cfname,no,no,2,2,raw_data,istat)
           dem_data=.true.
       else                                ! other  like albedo
!           CALL JCLGET(29,cfname,'FORMATTED',0,istatus)
           OPEN(29,FILE=cfname,FORM='FORMATTED',STATUS='OLD')
           CALL VFIREC(29,raw_data,no*no,'LIN')
           if ((ctiletype.eq.'U').and.(no.eq.121)) then
                dem_data=.false.           ! topo_30s
           endif
       endif

       if(istat.ne.0)then
          print*,'Error returned: proc_geodat: READ_DEM'
          istatus=0
          return
       endif
c
c make "super tile" from all smaller tiles
c
       read(ctilename(1:2),'(i2.2)')icurNS
       read(ctilename(3:3),'(a1)')curNS
       read(ctilename(4:6),'(i3.3)')icurEW
       read(ctilename(7:7),'(a1)')curEW

c      print*,'compute itiley/itilex'
       if(curNS .eq. 'S') icurNS=-1.0*icurNS
       itiley=nint(1.0+(float(icurNS)-tile_s_lat)/float(itilesize_d))
c
       rlondif=float(itile_lon(itile))-tile_w_lon
       if(rlondif.lt.0)then
          rlondif=rlondif+360.
       elseif(rlondif.ge.360)then
          rlondif=rlondif-360
       endif

       itilex=nint(1.0+(rlondif/float(itilesize_d)))

       itx=1+(itilex-1)*nx_tile
       ity=1+(itiley-1)*ny_tile

       print*,'itilex/itiley ',itilex,itiley
       print*,'itx/ity ',itx,ity

       jj=0
       do iy=ity,ny_tile*itiley
          jj=jj+1
          ii=0
          do ix=itx,nx_tile*itilex
             ii=ii+1
             data_proc(ix,iy,:)=raw_data(ii,jj,:)
          enddo
       enddo

      ENDDO

      deallocate (raw_data,itile_lat,itile_lon,ctile_name_list)

      print*,'initializing hinterp grx/gry arrays'

      print*,'nxst= ',nxst
      print*,'nyst= ',nyst
      print*,'dlat= ',dlat
      print*,'dlon= ',dlon
      print*,'lat0= ',lat0
      print*,'lon0= ',lon0

      call init_hinterp(nxst,nyst,nx_dom,ny_dom,'LL',
     .dom_lats_in,dom_lons_in,grx,gry,bgmodel,
     &lat0,lon0,dlat,dlon,cgrddef)

      print*,'grid rx/ry computed'
      print*,'SW: grx/gry    1,1: ',grx(1,1),gry(1,1)
      print*,'SE: grx/gry   nx,1: ',grx(nx_dom,1),gry(nx_dom,1)
      print*,'NW: grx/gry   1,ny: ',grx(1,ny_dom),gry(1,ny_dom)
      print*,'NE: grx/gry  nx,ny: ',grx(nx_dom,ny_dom)
     .,gry(nx_dom,ny_dom)

c compute mean value to use as def_value

      is=nint(MINVAL(grx))
      ie=nint(MAXVAL(grx))
      js=nint(MINVAL(gry))
      je=nint(MAXVAL(gry))

      print*,'is/ie/js/je ',is,ie,js,je

      do k=1,ncat
         asum(k)=0.0
         icnta=0
         do j=js,je
         do i=is,ie
            if(data_proc(i,j,k).ne.0.0)then
              icnta=icnta+1
              asum(k)=asum(k)+data_proc(i,j,k)
            endif
         enddo
         enddo
         if(icnta.gt.0)then
            amean(k)=asum(k)/icnta
         else
            amean(k)=r_missing_data
         endif
      enddo

      allocate (lmask_src(nxst,nyst))
      make_srcmask=.true.
      val_mask = 1
      nt=1

      if(ctiletype.eq.'T')then

         min_val = 239.73
         max_val = 305.09
         method  = 1
         geodat(:,:,:)=r_missing_data

      elseif(ctiletype.eq.'A')then

         min_val = 2.0
         max_val = 100.
         method  = 2
         where(amean .eq. r_missing_data)amean=18.

      elseif(ctiletype.eq.'G')then

         min_val = 1.0
         max_val = 100.
         method  = 2
         where(amean .eq. r_missing_data)amean=65.

      elseif(ctiletype.eq.'M')then

         min_val = 1.0
         max_val = 100.
         method  = 1
         geodat(:,:,:)=65.

      endif

      do ii=1,ncat

         def_val = amean(ii)

         call interpolate_masked_val(nxst, nyst
     ., lmask_src, data_proc(1,1,ii), nx_dom, ny_dom, lmask_out
     ., geodat(1,1,ii), grx, gry, make_srcmask, min_val, max_val
     ., def_val, val_mask, method)

         if(ctiletype.eq.'A'.or.ctiletype.eq.'M')then
            geodat(:,:,ii)=geodat(:,:,ii)/100.
         endif

         if(ctiletype.eq.'T')then  !.or.ctiletype.eq.'M')then
            print*,'Filering Deep Soil Temp with 1-2-1'
            call one_two_one(nx_dom,ny_dom,nt,geodat(1,1,ii))
         endif

      enddo

      deallocate (data_proc,lmask_src)

! --------------------------------------------------------
! ---- we are not yet processing categorical data (like
! ---- landuse or soil type, so this section is commented
! ---- for now.
! --------------------------------------------------------
! Loop over the raw data points in the tile

!       DO jt = 1, ny_tile
!       DO it = 1, nx_tile

! Compute lat/lon of this raw data point using lat/lon from
! file name, the offset of the data, and the increment

!        raw_lat = float(ilat) + RSOFF + (jt-1)*dlat_tile
!        raw_lon = float(ilon) + RWOFF + (it-1)*dlon_tile

! Use lat/lon to ij to find wheter this tile point is in our domain

!        call latlon_to_rlapsgrid(raw_lat,raw_lon,dom_lats_in
!    &                ,dom_lons_in,nx_dom,ny_dom,ri,rj,istatus)
!        dom_i = NINT(ri)
!        dom_j = NINT(rj)
!        IF( (dom_i .GE. 1).AND.(dom_i .LE. nx_dom).AND.
!    &   (dom_j .GE. 1).AND.(dom_j .LE. ny_dom) ) THEN

!         if(ctiletype.eq.'V')then

!            point_value=int(raw_data(it,jt,1))
!            num_raw_points_cat(dom_i,dom_j,point_value) =
!    &       num_raw_points_cat(dom_i,dom_j,point_value) + 1

!            num_raw_points_total(dom_i, dom_j) =
!    &       num_raw_points_total(dom_i, dom_j)+ 1

!         elseif(ctiletype.eq.'T')then

!            num_raw_points_cat(dom_i,dom_j,1) =
!    &       num_raw_points_cat(dom_i,dom_j,1)+1

!            num_raw_points_total(dom_i, dom_j) =
!    &       num_raw_points_total(dom_i, dom_j)+raw_data(it,jt,1)

!         endif
         
!         ! The point is in our domain, so increment the counters.  The 
          ! value of the raw data point is equal to the category ID for
          ! things like veg-type and soil-type.  For topography, we would
          ! have to have additional arrays to keep the sum of the terrain
          ! values to compute the average value at the end. This example
          ! code only does category data

!        ENDIF
!       ENDDO
!       ENDDO 


! Now you can compute percentage of each category like so:
!     if(ctiletype.eq.'V')then
!        DO icat = 1, ncat
!           cat_pct(:,:,icat)=num_raw_points_cat(:,:,icat) / 
!    &                         num_raw_points_total(:,:)
!        ENDDO
!     elseif(ctiletype.eq.'T')then
!           cat_pct(:,:,1)= num_raw_points_total(:,:)/
!    &                       num_raw_points_cat(:,:,1)
!     endif

      return

1000  print*,'returning to main. no data processed'
      return

      end
c
c-----------------------------------------------------------
c

      subroutine one_two_one(nx,ny,nt,data) 1

      implicit none
      integer i,j,ii,jj,icnt,n
      integer nx,ny,nt
      integer istatus
      real  r_missing_data
      real  fact,sum
      real  data(nx,ny)
      real, allocatable :: temp(:,:)

      allocate(temp(nx,ny))

!      call get_r_missing_data(r_missing_data,istatus)
      r_missing_data = 1e+37

      temp=data

      do n=1,nt

         do j=2,ny-1
         do i=2,nx-1

            sum=0.0
            icnt=0
            do jj=j-1,j+1
            do ii=i-1,i+1

               fact=1
               if(jj==j.and.ii==i)fact=2
               if(data(ii,jj).lt.r_missing_data)then
                  icnt=icnt+fact
                  sum=sum+data(ii,jj)*fact
               endif

            enddo
            enddo

            if(icnt.gt.0)then
               temp(i,j)=sum/float(icnt)
            else
               temp(i,j)=data(i,j)
            endif

         enddo
         enddo

         data=temp

      enddo

      deallocate (temp)

      return
      end


      subroutine get_tile_list(min_lat,max_lat,min_lon,max_lon 1
     1,maxtiles,isbego,iwbego,itilesize,ctiletype
     1,num_tiles_needed,ctile_name_list,iwoc1,iwoc2
     1,isoc1,isoc2,istatus)

      implicit  none

      real      max_lat,min_lat
      real      max_lon,min_lon

      integer   num_tiles_needed
      integer   isbego,iwbego
      integer   itilesize
      integer   itile_ns
      integer   iwoc0
      integer   iwoc,iwoc1,iwoc2
      integer   isoc,isoc1,isoc2
      integer   isocpt,isocpo
      integer   iwocpt,iwocpo,iwocph
      integer   iwocdif
      integer   istatus
      integer   maxtiles


      character*1 ctiletype
      character*3 nstitle
      character*4 ewtitle
      character*8 ctilenamelist(500)
      character*(*) ctile_name_list(maxtiles)

      double precision r8term

      istatus = 1

      r8term=(min_lat-float(isbego))/float(itilesize)
      ISOC1=(INT(r8term+200.)-200)*itilesize+ISBEGO
      r8term=(min_lon-float(iwbego))/float(itilesize)
      IWOC1=(INT(r8term+400.)-400)*itilesize+IWBEGO
      r8term=(max_lat-float(isbego))/float(itilesize)
      ISOC2=(INT(r8term+200.)-200)*itilesize+ISBEGO
      r8term=(max_lon-float(iwbego))/float(itilesize)
      IWOC2=(INT(r8term+400.)-400)*itilesize+IWBEGO

      num_tiles_needed=0

      if(IWOC1.lt.-180)then
         if(itilesize.eq.180)then
            iwocdif=iwoc2-iwoc1
            IWOC1=IWOC1+IWOCDIF
            IWOC2=IWOC2+abs(IWOCDIF)
c        else
c           IWOC1=360+IWOC1
         endif
c     elseif(IWOC1.gt.180)then
c        IWOC1=360-IWOC1
      endif
      print*,'Noddy IWOC1, IWOC2 ',IWOC1,IWOC2
      do IWOC = IWOC1,IWOC2,itilesize

         IWOC0 = IWOC
         IF(IWOC.LT.-180)IWOC0=360+IWOC0
c        IF(IWOC.GT.+180)IWOC0=360-IWOC0

         IWOCPH=ABS(IWOC0)/100
         IWOCPT=(ABS(IWOC0)-IWOCPH*100)/10
         IWOCPO=ABS(IWOC0)-IWOCPH*100-IWOCPT*10
!
! TH: 8 Aug 2002 We now allow 180E longitudes (and greater). The only 
! time we want to assign W is when the longitude is less than 0.
!
         IF(IWOC0.GE.0.and.IWOC0.LT.180) THEN
            WRITE(EWTITLE,'(3I1,A1)')IWOCPH,IWOCPT,IWOCPO,'E'
         ELSE
            WRITE(EWTITLE,'(3I1,A1)')IWOCPH,IWOCPT,IWOCPO,'W'
         ENDIF

         if(ewtitle(1:1).eq.' ')ewtitle(1:1)='0'
         if(ewtitle(2:2).eq.' ')ewtitle(2:2)='0'

c        ewtitle=ewtitle2//ewtitle1

         do ISOC = ISOC1,ISOC2,itilesize

            ISOCPT=ABS(ISOC)/10
            ISOCPO=ABS(ISOC)-ISOCPT*10

            IF(ISOC.GE.0)THEN
              WRITE(NSTITLE,'(2I1,A1)')ISOCPT,ISOCPO,'N'
            ELSE
              WRITE(NSTITLE,'(2I1,A1)')ISOCPT,ISOCPO,'S'
            ENDIF

            num_tiles_needed=num_tiles_needed+1
            ctilenamelist(num_tiles_needed)=nstitle//ewtitle

         enddo
      enddo

      if(num_tiles_needed.eq.3.and.maxtiles.eq.2)then
         num_tiles_needed = 2
      endif

      if(num_tiles_needed.le.maxtiles)then
         do itile_ns=1,num_tiles_needed
            ctile_name_list(itile_ns)=ctilenamelist(itile_ns)
         enddo
      else
         print*,'more tiles than array allocation'
         istatus = 0
      endif

      return
      end



      subroutine adjust_geog(nnxp,nnyp,ncat,ctype 4,3
     &,istat_dat,lat,topt_out           !istattmp,istatslp,lat,topt_out,path_to_soiltemp
     &,landmask,geog_data,istatus)      !soiltemp_1deg,greenfrac,islope,istatus)
c
c This routine uses landmask to make the course resolution
c soil temp and green fraction data conform to water-land mask.
c It also fills small islands or isolated land
c bodies with appropriate geog values as necessary
c
c J. Smart NOAA/FSL
c     "    06-22-01 original
c     "    12-01-03 put subroutine into gridgen_utils, make arrangements for soil
c                   type data, and allow separate calls for each geog type to reduce
c                   memory requirement.
c
      implicit none

      integer nnxp,nnyp
      integer i,j,l,ii,jj
      integer is,js
      integer istatus
      integer istat_dat    !Input. =0 indicates input geog data was NOT processed properly; =1 otherwise.
      integer ijsthresh    !search distance to look for representative vlues to fill inconsistency.
      integer isum
      integer l1,l2
      integer lent
      integer ncat
      integer ifixw,ifixl
      integer ifixws,ifixwt,ifixls

      integer isc
      integer ic(ncat) 

      character*132 path_to_soiltemp
      character*(*) ctype

      logical endsearch

      real,intent(inout)  ::    lat(nnxp,nnyp)
      real,intent(inout)  ::    landmask(nnxp,nnyp)
      real,intent(inout)  ::    topt_out(nnxp,nnyp)
      real,intent(inout)  ::    geog_data(nnxp,nnyp,ncat)

c     real,intent(inout)  ::    soiltemp_1deg(nnxp,nnyp)
c     real,intent(inout)  ::    greenfrac(nnxp,nnyp,ncat)
c     real,intent(inout)  ::    islope(nnxp,nnyp)

      real,   allocatable ::    geog_tmp      (:,:,:) !temporary holder of input geog data.

c     real,   allocatable ::    grnfrctmp     (:,:,:)
c     real,   allocatable ::    soiltmp       (:,:)
c     real,   allocatable ::    islopetmp     (:,:)

      real,   allocatable ::    rmeanlattemp  (:)

      real    avgtmp
      real    avggrn(ncat)
      real    avgcat
      real    tatlmx,tatlmn
      real    rlatmx,rlatmn
      real    r_missing_data
      real    rmngrn
      real    islp
      real    sumt
      real    sumg
      real    sum(ncat)
      real    tslp

      istatus=0
      if(istat_dat.eq.0)then  !.and.istattmp.eq.0.and.istatslp.eq.0)then
	 print*,'Unable to process geog data in adjust_geog ...'
     &,' processsing of data failed prior to subroutine call.'
	 return
      endif


c use moist adiabatic laps rate (6.5 deg/km) to get new temp
 
      allocate (geog_tmp(nnxp,nnyp,ncat))

!      call get_r_missing_data(r_missing_data,istatus)
      r_missing_data = 1e+37

      geog_tmp=geog_data

      where(geog_tmp.eq.0.0)geog_tmp=r_missing_data

      if(ctype.eq.'greenfrac')then
         rmngrn=minval(geog_tmp(1:nnxp,1:nnyp,1:1))
         print*,'minimum green fraction = ',rmngrn
      endif

c determine average soiltemp and greenfrac in domain
      sumt=0.0
      sum=0.0
      isc=0
      ic=0
      islp=0
      isum=0
      if(ctype.eq.'soiltemp')then
         do j = 1,nnyp
         do i = 1,nnxp
            if(geog_tmp(i,j,1).ne. r_missing_data)then
               sumt=geog_tmp(i,j,1)+sumt
               isc=isc+1
            endif
         enddo
         enddo
      elseif(ctype.eq.'greenfrac')then
c greenfrac is assumed to be continuous globally; only use land points
         do j = 1,nnyp
         do i = 1,nnxp
            do l=1,ncat
               if(landmask(i,j) .ne. 0 .and.
     &geog_tmp(i,j,l).lt.r_missing_data)then
                  sum(l)=geog_tmp(i,j,l)+sum(l)
                  ic(l)=ic(l)+1
               endif
            enddo
         enddo
         enddo
      elseif(ctype.eq.'islope'.or.ctype.eq.'soiltype')then
         do j = 1,nnyp
         do i = 1,nnxp
            if(geog_tmp(i,j,1).ne. r_missing_data)then
               isum=geog_tmp(i,j,1)+isum
               islp=islp+1
            endif
         enddo
         enddo
      endif
c
c get average information for filling as necessary
c ----------------------------------------------------
c
c 1. deep soil temp.
c
      if(isc.gt.0)then
         avgtmp=sumt/float(isc)
         print*,'Domain average annual mean temp = ',avgtmp
      elseif(ctype.eq.'soiltemp')then
c
c this section uses mean latitudinally averaged temps derived from 
c the raw 1 deg temp data. File in raw geog annual mean deep soil
c temp directory (see wrfsi.nl variable soiltemp_1deg).
c
         call get_path_to_soiltemp_1deg(path_to_soiltemp,istatus)
         sumt=0.0
         print*,'*** Using mean lat temps -> LATMEANTEMP ***'
         allocate (rmeanlattemp(180))
         call  get_directory_length(path_to_soiltemp,lent)
         call  get_meanlattemp(path_to_soiltemp(1:lent-1)
     &,rmeanlattemp,istatus)
         if(istatus.ne.1)then
            print*,'Error returned: get_meanlattemp'
            return
         endif
         l1=90-nint(minval(lat(:,1)))+1
         l2=90-nint(maxval(lat(:,nnyp)))+1
         if(l1.gt.180)l1=180
         if(l2.gt.180)l2=180

         rlatmn=minval(lat(:,1))
         rlatmx=maxval(lat(:,nnyp))
         tatlmx=rmeanlattemp(l2)
         tatlmn=rmeanlattemp(l1)
         if(tatlmx.ne.0.and.tatlmn.ne.0.and.
     .      tatlmx.ne.tatlmn)then
            tslp=(rlatmx-rlatmn)/(tatlmx-tatlmn)
            do j=1,nnyp
            do i=1,nnxp
               geog_tmp(i,j,1)=tatlmn+(rlatmx-lat(i,j))/tslp
               sumt=geog_tmp(i,j,1)+sumt
            enddo
            enddo
            avgtmp=sumt/(nnyp*nnxp)
         elseif(tatlmx.gt.0)then
            avgtmp=tatlmx
         elseif(tatlmn.gt.0)then
            avgtmp=tatlmn
         else
            print*,'Unusual condition with meanlattemp'
            istatus = 0
            return
         endif
         deallocate (rmeanlattemp)
         print*,'Domain average annual mean temp = ',avgtmp
      endif
c
c 2. green fraction.
c
      if(ctype.eq.'greenfrac')then
         avggrn=r_missing_data
         do l=1,ncat
            if(ic(l).gt.0)then
               avggrn(l)=sum(l)/float(ic(l))
            else
               avggrn(l)=0.0
            endif
            print*,'Domain average greenfrac = ',l,avggrn(l)
         enddo
c
c 3. Terrain slope index or soil type category..
c
      elseif(ctype.eq.'islope'.or.ctype.eq.'soiltype')then
        avgcat=r_missing_data
        if(islp.gt.0)then
           avgcat=float(isum)/islp
           print*,'Average category: ',avgcat
        else
           print*,'Could not compute average category ?'
           print*,'Average category: ',avgcat
        endif
      endif

c extend search to a fraction of the domain size. Could improve this for
c ratio geog-data-res/domain-res (possibly) to avoid unreasonable
c search distance.

      ijsthresh = int(nnxp/2)
      ifixw=0
      ifixl=0

      if(ctype.eq.'soiltemp')then

         do j = 1,nnyp
         do i = 1,nnxp

            if(landmask(i,j).eq.1)then                   !a land point
               if(geog_tmp(i,j,1).eq.r_missing_data)then !inconsistent because it is water
 
                  is=1
                  js=1
                  endsearch = .false.

                  sumt=0.0
                  isc=0

                  do while (.not.endsearch)

                   do jj=j-js,j+js
                   do ii=i-is,i+is

                      if((ii.ge.1) .and. (ii.le.nnxp) .and.
     &                   (jj.ge.1) .and. (jj.le.nnyp)) then

                       if(geog_tmp(ii,jj,1).ne.r_missing_data)then
                          sumt=sumt+geog_tmp(ii,jj,1)
                          isc=isc+1
                       endif

                      endif

                   enddo
                   enddo

                   if(isc.gt.0)then
                      geog_data(i,j,1)=-0.0065*topt_out(i,j)+sumt/isc
                      ifixw=ifixw+1    !count the # of inconsistent water points fixed with rep land value
                      endsearch=.true.
                   else
                      is=is+1
                      js=js+1
                      if(is.gt.ijsthresh)endsearch=.true.
                   endif

                  enddo

               else  !no inconsistency

                  geog_data(i,j,1)=-0.0065*topt_out(i,j)
     &+geog_data(i,j,1)

               endif

            else     !landmask says this is a water point

               if(geog_tmp(i,j,1).ne.r_missing_data)then
                  geog_data(i,j,1)=r_missing_data
                  ifixl=ifixl+1            !count the # of fixed land points
               endif

            endif

         enddo
         enddo

      elseif(ctype.eq.'greenfrac')then

         do j = 1,nnyp
         do i = 1,nnxp

            if(landmask(i,j).eq.1)then                  !a land point

               if(geog_tmp(i,j,1).eq.r_missing_data
     &.and.rmngrn.lt.r_missing_data)then  !inconsistency and there is valid data to search for.

                  endsearch = .false.

                  sum=0.0
                  ic=0
                  is=1
                  js=1
        
                  do while (.not.endsearch)

                   do ii=i-is,i+is
                   do jj=j-js,j+js

                    if( (ii.ge.1) .and. (ii.le.nnxp)
     &             .and.(jj.ge.1) .and. (jj.le.nnyp)) then

                       if(landmask(ii,jj).eq.1.and.
     &         geog_tmp(ii,jj,1).lt.r_missing_data)then

                          do l=1,12
                             sum(l)=sum(l)+geog_tmp(ii,jj,l)
                             ic(l)=ic(l)+1
                          enddo
                       endif

                    endif

                   enddo
                   enddo

                   if(ic(1).gt.0)then
                      do l=1,12
                         geog_data(i,j,l)=sum(l)/float(ic(l))
                      enddo
                      ifixw=ifixw+1
                      endsearch=.true.
                   else
                      is=is+1
                      js=js+1
                      if(is.gt.ijsthresh.or.js.gt.ijsthresh)
     &                   endsearch=.true.
                   endif

                  enddo

               else

                  geog_data(i,j,:)=geog_tmp(i,j,:)

               endif

            else  !this is a water point

c              do l=1,12
c                 if(geog_tmp(i,j,l).ne. 0.0 .and.
c    &               geog_tmp(i,j,l).lt.r_missing_data)then
c                    geog_data(i,j,l)=0.0
c                    ifixl=ifixl+1  !count # of land points that should be water
c                 endif
c              enddo

               if(geog_tmp(i,j,1).ne. 0.0 .and.
     &               geog_tmp(i,j,1).lt.r_missing_data)then
                     geog_data(i,j,1:12)=0.0
                     ifixl=ifixl+1  !count # of land points that should be water
               endif

            endif

         enddo
         enddo
c
c -------------------------------------------------------
c this section for categories (terrain slope or soiltype)
c
      elseif(ctype.eq.'islope'.or.ctype.eq.'soiltype')then

         do j = 1,nnyp
         do i = 1,nnxp

            if(landmask(i,j).eq.1)then                  !a land point

               if(geog_tmp(i,j,1).eq.r_missing_data)then !an inconsistency

                  endsearch = .false.

                  sumt=0.0
                  isc=0
                  islp=-9
                  is=1
                  js=1

                  do while (.not.endsearch)
                     do ii=i-is,i+is
                     do jj=j-js,j+js

                        if( (ii.ge.1) .and. (ii.le.nnxp)
     &                 .and.(jj.ge.1) .and. (jj.le.nnyp)) then

                           if(landmask(ii,jj).eq.1.and.
     &                        geog_tmp(ii,jj,1).lt.r_missing_data)then
                              islp=geog_tmp(ii,jj,1)
                              sumt=sumt+islp
                              isc=isc+1
                           endif

                        endif

                     enddo
                     enddo
 
                     if(ctype.eq.'islope')then
                        if(isc.gt.0)then
                           if(islp.gt.7.0)islp=13.0 !force mean to glacial ice as necessary
                           if(sumt.lt.isc)then
                              islp=1.0
                           else
                              islp=float(nint(sumt/float(isc)))
                           endif
                           geog_data(i,j,1)=islp
                           endsearch=.true.
                           ifixw=ifixw+1  !water point fixed to be land point
                        else
                           is=is+1
                           js=js+1
                           if(is.gt.ijsthresh.or.js.gt.ijsthresh)
     &                        endsearch=.true.
                        endif
                     else
                        if(isc.gt.0)then
                           if(sumt.lt.isc)then
                              islp=1.0
                           else
                              islp=float(nint(sumt/float(isc)))
                           endif
                           geog_data(i,j,1)=islp
                           endsearch=.true.
                           ifixw=ifixw+1  !water point fixed to be land point
                        else
                           is=is+1
                           js=js+1
                           if(is.gt.ijsthresh.or.js.gt.ijsthresh)
     &                        endsearch=.true.
                        endif
                     endif

                  enddo

               else

                  geog_data(i,j,1)=geog_tmp(i,j,1)

               endif

            else     !this is a water point

               if(geog_tmp(i,j,1).ne.r_missing_data)then
                  geog_data(i,j,1)=r_missing_data
                  if(ctype.eq.'islope')
     &            ifixl=ifixl+1   !land point fixed to be water point
               endif

            endif

         enddo
         enddo

      else

         print*,'Unknown type input to adjust_geog!'
         return

      endif ! ctype switch

      deallocate (geog_tmp)

c if the above search failed to find nearby soil temp or greenness frac
c then use average value

      if(ctype.eq.'soiltemp')then
         do j = 1,nnyp
         do i = 1,nnxp
            if(landmask(i,j).eq.1)then  !a land point
               if(geog_data(i,j,1).eq.r_missing_data)then
                  geog_data(i,j,1) = avgtmp-0.0065*topt_out(i,j)
                  ifixw=ifixw+1
               endif
            endif
         enddo
         enddo
         print*
         print*,'Soil Temp stats'

      elseif(ctype.eq.'greenfrac')then

         do j = 1,nnyp
         do i = 1,nnxp
            if(landmask(i,j).eq.1)then  !a land point
               do l = 1,12
                  if(geog_data(i,j,l).eq.0.0)then
                     geog_data(i,j,l)=float(nint(avggrn(l)))
                     if(l==1)ifixw=ifixw+1
                  endif
               enddo
            endif
         enddo
         enddo
         print*
         print*,'Green fraction stats'

      elseif(ctype.eq.'islope'.or.ctype.eq.'soiltype')then

         do j = 1,nnyp
         do i = 1,nnxp

            if(landmask(i,j).eq.1)then  !a land point
               if(geog_data(i,j,1).eq.r_missing_data)then
                  geog_data(i,j,1)=float(nint(avgcat))
                  if(ctype.eq.'islope')then
                     ifixw=ifixw+1
                  else
                     ifixl=ifixl+1
                  endif
               endif
            endif

        enddo
        enddo
        print*
        if(ctype.eq.'islope')then
           print*,'Terrain Slope Index stats'
        else
           print*,'Soil Type Category stats'
        endif

        where(geog_data.eq.r_missing_data)geog_data=0.0  !put water category back to original value

      else

        print*,'unknown geog data from ctype ',ctype

      endif

      print*,'--------------------------'
      if(ctype.ne.'islope'.and.ctype.ne.'soiltype')then
         if(ctype.eq.'greenfrac')then
            print*,'Fixed ',ifixw,'  points with rep land value'
            print*,'Fixed ',ifixl,'  points with missing value = water'
            print*
            do j = 1,nnyp
            do i = 1,nnxp
            do l = 1,ncat
               if(landmask(i,j) .ne. 0 .and.
     &geog_data(i,j,l).gt.0.0)then
                  sum(l)=geog_data(i,j,l)+sum(l)
                  ic(l)=ic(l)+1
               endif
            enddo
            enddo
            enddo
            do l=1,ncat
               if(ic(l).gt.0)then
                  avggrn(l)=sum(l)/float(ic(l))
               else
                  avggrn(l)=0.0
               endif
               print*,'Domain average greenfrac = ',l,avggrn(l)
            enddo
         else
            print*,'Fixed ',ifixw,'  points with rep land value'
            print*,'Fixed ',ifixl,'  points with missing value = water'
         endif
      elseif(ctype.eq.'islope')then
         print*,'Fixed ',ifixw,'  points with rep land value'
         print*,'Fixed ',ifixl,'  points with missing value = water'
      else
         print*,'Fixed ',ifixw,'  points with rep land value'
         print*,'Fixed ',ifixl,'  points with missing value = water'
      endif

      istatus=1

      return
      end


      subroutine filter_2dx(field,ix,iy,iz,smth) 2
c
c *** Subprogram:  smooth - Smooth a meteorological field.
c     Author:  Stan Benjamin 
c     Date  :  90-06-15
c
c *** Abstract:  Shapiro smoother. 
c 
c *** Program history log: 
c        85-12-09  S. Benjamin - Original version
c        96-06-16  J. Snook    - Modified to do 3d RAMS fields
c                              - hold array is dynamically allocated
c 
c *** Usage:  call smooth(field,ix,iy,iz,smth) 
c
c *** Input argument list: 
c        field    - real array  field(ix,iy,iz)
c                               Meteorological field
c        ix       - integer     x coordinates of field
c        iy       - integer     y coordinates of field
c        iz       - integer     z coordinates of field
c        smth     - real      
c
c *** Output argument list:   
c        field    - real array  field(ix,iy,iz)
c                               Smoothed meteorological field
c 
c *** Remarks:  Reference:  Shapiro, 1970: "Smoothing, filtering, and
c        boundary effects", Rev. Geophys. Sp. Phys., 359-387.
c
c     This filter is of the type 
c        z(i) = (1-s)z(i) + s(z(i+1)+z(i-1))/2
c     for a filter which is supposed to damp 2dx waves completely
c     but leave 4dx and longer with little damping,
c     it should be run with 2 passes using smth (or s) of 0.5
c     and -0.5.
c_______________________________________________________________________________
c   
      
c
      integer ix,iy,iz,i,j,k,i1,i2,it
c
      real field(ix,iy,iz),
     .     hold(ix,2),
     .     smth,smth1,smth2,smth3,smth4,smth5,
     .     sum1,sum2
c_______________________________________________________________________________
c
      smth1=0.25*smth*smth
      smth2=0.50*smth*(1.-smth)
      smth3=(1.-smth)*(1.-smth)
      smth4=(1.-smth)
      smth5=0.5*smth
c
      do k=1,iz
c
         do j=1,2
         do i=1,ix
            hold(i,j)=0.
         enddo
         enddo
c
         i1=2
         i2=1
         do j=2,iy-1
            it=i1
            i1=i2
            i2=it
            do i=2,ix-1
               sum1=field(i-1,j+1,k)+field(i-1,j-1,k)
     .             +field(i+1,j+1,k)+field(i+1,j-1,k)
               sum2=field(i  ,j+1,k)+field(i+1,j  ,k)
     .             +field(i  ,j-1,k)+field(i-1,j  ,k)
               hold(i,i1)=smth1*sum1+smth2*sum2+smth3*field(i,j,k)
            enddo
            if (j .eq. 2) goto 200
            do i=2,ix-1
               field(i,j-1,k)=hold(i,i2)
            enddo
200         continue
         enddo
c
         do i=2,ix-1
            field(i,iy-1,k)=hold(i,i1)
         enddo
c
         do i=2,ix-1
            field(i,1,k)=smth4*field(i,1,k) 
     .                  +smth5*(field(i-1,1,k)+field(i+1,1,k))
            field(i,iy,k)=smth4*field(i,iy,k) 
     .                   +smth5*(field(i-1,iy,k)+field(i+1,iy,k))
         enddo
c
         do j=2,iy-1
            field(1,j,k)=smth4*field(1,j,k) 
     .                  +smth5*(field(1,j-1,k)+field(1,j+1,k))
            field(ix,j,k)=smth4*field(ix,j,k) 
     .                   +smth5*(field(ix,j-1,k)+field(ix,j+1,k))
         enddo
c
      enddo
c
      return
      end

c
c ---------------------------------------------------------------
c

      subroutine get_meanlattemp(path_to_tiles,temp,istat) 1
c
      implicit      none

      integer       istat
      integer       n,i
      integer       ldir
      character*(*) path_to_tiles

      real          temp(180)

      istat=0
!      call s_len(path_to_tiles,ldir)
      ldir = LEN_TRIM(path_to_tiles)

      open(22,file=path_to_tiles(1:ldir)//'/LATMEANTEMP.DAT'
     &,form='formatted',status='old',iostat=istat)
      if(istat.ne.0) then
	write(6,*) 'insert bogus temp of 280'
	temp=280.0
	istat=1
	return
!	goto 3
      endif
      do i=1,180
         read(22,222,err=4)temp(i)
      enddo
 
      close(22)

      istat=1

      return

c     print*,'rmeantemp 1/2/3/4/5; ',rmeantemp(1),rmeantemp(45),rmeantemp(90)&
c          ,rmeantemp(135),rmeantemp(180)

222   format(1x,f6.2)

  3   print*,'Error: opening LATMEANTEMP file '
      print*,'path_to_tiles: ',path_to_tiles(1:ldir+3),ldir
      return
  4   print*,'Error: reading LATMEANTEMP file '

      return
      end

c
c===============================================================================
c

      subroutine init_hinterp(nx_bg,ny_bg,nx_laps,ny_laps,gproj, 1,1
     .     lat,lon,grx,gry,bgmodel,
     &     lat0,lon0,dlat,dlon,cgrddef)

! only part in subourine init_hinterp of WRFSI file lib/gridconv.f was copied.
!
      implicit none

      integer nx_bg,ny_bg,nx_laps,ny_laps,bgmodel

      real*4 lat(nx_laps,ny_laps),lon(nx_laps,ny_laps),
     .       grx(nx_laps,ny_laps),gry(nx_laps,ny_laps)

      character*1  cgrddef 
      character*2  gproj

      real   dlat, dlon
      real   lat0, lon0

      integer i,j,k
      integer istatus

      integer lenc

      integer nxc,nyc,nzc
      integer nx,ny
      logical lprintmessage
      real sw(2),ne(2),rota
      real nw(2),se(2),rlatc,rlonc
      real tolx,toly
      real grxdifsum1,grxdifsum2
      real grydifsum1,grydifsum2
      real r_missing_data
c________________________________________________________________________________
c
!      call get_r_missing_data(r_missing_data,istatus)

      r_missing_data = 1.e+37
      istatus = 1

      if(istatus.ne. 1)then
         print*,'Error getting r_missing_data - init_hinterp'
         return
      endif
c
c *** Determine location of LAPS grid point in background data i,j space.
c
      if (gproj .eq. 'LL') then
         call latlon_2_llij(nx_laps*ny_laps,lat,lon,grx,gry,
     &                      lat0,lon0,dlat,dlon,cgrddef)
      else
         print*,"Error: Unknown gproj spec in gridconv ",gproj
      endif
c
c *** Check that all LAPS grid points are within the background data coverage.
c

c set tolerance based upon the grid spacing as a function of grx/gry
      grxdifsum1=0.0
      grxdifsum2=0.0
      grydifsum1=0.0
      grydifsum2=0.0
      do j=1,ny_laps
         grxdifsum1=grxdifsum1+(grx(2,j)-grx(1,j))
         grxdifsum2=grxdifsum2+(grx(nx_laps-1,j)-grx(nx_laps,j))
      enddo
      do i=1,nx_laps
         grydifsum1=grydifsum1+(gry(i,2)-gry(i,1))
         grydifsum2=grydifsum2+(gry(i,ny_laps-1)-gry(i,ny_laps))
      enddo

      tolx=(abs(grxdifsum1)/ny_laps+abs(grxdifsum2)/ny_laps)*0.5
      toly=(abs(grydifsum1)/nx_laps+abs(grydifsum2)/nx_laps)*0.5

      print*,'horiz mapping tolerance x/y: ',tolx,toly
      lprintmessage=.true.
c
c *** First, check for wrapping if a global data set.
c
      if ( bgmodel .eq. 6 .or. 
     .     bgmodel .eq. 8) then
         do j=1,ny_laps
            do i=1,nx_laps
               if (grx(i,j) .lt. 1.) grx(i,j)=grx(i,j)+float(nx_bg)
               if (grx(i,j) .gt. nx_bg) grx(i,j)=grx(i,j)-float(nx_bg)
               if (gry(i,j) .lt. 1.) then
                  gry(i,j)=2.-gry(i,j)
                  grx(i,j)=grx(i,j)-float(nx_bg/2)
                  if (grx(i,j) .lt. 1.) grx(i,j)=grx(i,j)+float(nx_bg)
                  if (grx(i,j).gt.nx_bg) grx(i,j)=grx(i,j)-float(nx_bg)
               endif
               if (gry(i,j) .gt. ny_bg) then
                  gry(i,j)=float(2*ny_bg)-gry(i,j)
                  grx(i,j)=grx(i,j)-float(nx_bg/2)
                  if (grx(i,j) .lt. 1.) grx(i,j)=grx(i,j)+float(nx_bg)
                  if (grx(i,j).gt.nx_bg) grx(i,j)=grx(i,j)-float(nx_bg)
               endif
               if (grx(i,j) .lt. 1) then
                  grx(i,j)=grx(i,j)+1.
               endif
            enddo
         enddo
c
c ****** If not a global data set, then check that LAPS domain is fully
c           within background domain.
c
      else
         do j=1,ny_laps
            do i=1,nx_laps
c
c LAPS must fit into model grid which must also fit into LAPS grid thus we
c introduce a small fudge factor on the grid boundaries.
c               

               if(grx(i,j).gt.1.-tolx) grx(i,j) = max(1.,grx(i,j))
               if(gry(i,j).gt.1.-toly) gry(i,j) = max(1.,gry(i,j))

               if(grx(i,j).lt.float(nx_bg)+tolx) 
     +              grx(i,j) = min(float(nx_bg)-tolx,grx(i,j))
               if(gry(i,j).lt.float(ny_bg)+toly) 
     +              gry(i,j) = min(float(ny_bg)-toly,gry(i,j))

               if (grx(i,j) .lt. 1 .or. grx(i,j) .gt. nx_bg .or.
     .             gry(i,j) .lt. 1 .or. gry(i,j) .gt. ny_bg) then

                  grx(i,j) = r_missing_data
                  gry(i,j) = r_missing_data

           if(lprintmessage)then
              print*,'Domain gridpt outside of bkgd data coverage.'
              print*,'   data i,j,lat,lon - ',i,j,lat(i,j),lon(i,j)
              print*,'   grx, gry:',grx(i,j),gry(i,j)
              lprintmessage=.false.
c                 stop 'init_hinterp'
           endif

               endif
            enddo
         enddo
      endif
c
      return
      end