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