PROGRAM mrgtrn,16 ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Program to merge terrain files to insure continuity for ! external grids near boundaries while accepting smaller-scale ! terrain features in the interior. ! ! Steps: Read in 2 ARPS terrain files ! 1) large-scale external grid ! 2) fine-scale terrain on final grid ! Interpolate large scale terrain to fine scale grid ! Correct for any biases in the large-scale terrain ! Blend the two grids, using the large-scale data near ! the domain edge. ! Compilation/linking: ! ! f77 -o mergetrn mergetrn.o maproj3d.o \ ! extlib3d.o outlib3d.o iolib3d.o ibmlib3d.o ! ! AUTHOR: Keith Brewster ! 01/03/95 ! ! MODIFICATION HISTORY: ! 10/09/96 (K. Brewster) ! Corrected input of map parameters by adding routine rdtrnall. ! ! 06/10/97 (K. Brewster) ! Added option to leave a border of external terrain data before ! beginning the merging. The border is specific in the input file ! using iborder and jborder. ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! INCLUDE 'globcst.inc' INCLUDE 'grid.inc' INTEGER :: nx, ny INTEGER :: nx_ext, ny_ext ! REAL, allocatable :: xs(:),ys(:) REAL, allocatable :: xgr(:,:),ygr(:,:) REAL, allocatable :: lat(:,:),lon(:,:) REAL, allocatable :: hterain(:,:) REAL, allocatable :: hterain1(:,:) REAL, allocatable :: hterain2(:,:) REAL, allocatable :: hterout(:,:) REAL, allocatable :: work(:,:) INTEGER, allocatable :: iloc(:,:),jloc(:,:) ! REAL, allocatable :: xs_ext(:),ys_ext(:) REAL, allocatable :: terext(:,:) REAL, allocatable :: dxfld(:) REAL, allocatable :: dyfld(:) REAL, allocatable :: rdxfld(:) REAL, allocatable :: rdyfld(:) REAL, allocatable :: slopey(:,:) REAL, allocatable :: alphay(:,:) REAL, allocatable :: betay(:,:) INTEGER, allocatable :: iw(:,:) ! !----------------------------------------------------------------------- ! ! Terrain namelist variables ! !----------------------------------------------------------------------- ! REAL :: dx_ext,dy_ext CHARACTER (LEN=80) :: terndta_ext NAMELIST /terrain/ nx,ny,dx,dy,nx_ext,ny_ext,dx_ext,dy_ext, & terndta,terndta_ext INTEGER :: iborder,jborder REAL :: rlen INTEGER :: rmvbias,nsmth NAMELIST /ternmrg/ iborder,jborder,rlen,rmvbias,nsmth INTEGER :: ovrmap,mapcol,mapgrid REAL :: latgrid,longrid CHARACTER (LEN=80) :: mapfile NAMELIST /map_plot/ ovrmap,mapcol,mapgrid,latgrid,longrid, & mapfile ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! CHARACTER (LEN=80) :: ternfn REAL :: latnot(2) INTEGER :: i,j,lenstr,ksmth,iproj_ext,korder INTEGER :: istart,iend,jstart,jend REAL :: scale_ext,trulat1_ext,trulat2_ext REAL :: trulon_ext,ctrlat_ext,ctrlon_ext REAL :: xctr,yctr,x0_ext,y0_ext REAL :: x0,y0,sum,sum_ext,bias,wt REAL :: w1,w2,w3,w4,scalex,scaley INTEGER :: nxpic,nypic PARAMETER (nxpic=1,nypic=1) REAL :: sm PARAMETER (sm=0.5) INTEGER :: iorder PARAMETER (iorder=1) INTEGER :: ncl REAL :: cl(100) INTEGER :: iplt,mode REAL :: angl,xlimit,ylimit,xymax INTEGER :: istatus ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! iborder=0 jborder=0 rlen=10000. rmvbias=0 nsmth=0 ovrmap=1 mapcol=1 mapgrid=0 latgrid=10. longrid=10. WRITE(6,'(/a/)') & ' Please input control parameters for terrain merging.' READ(5,terrain,END=600) READ(5,ternmrg,END=600) READ(5,map_plot,END=600) allocate(xs(nx),ys(ny),stat=istatus) allocate(xgr(nx,ny),ygr(nx,ny),stat=istatus) allocate(lat(nx,ny),lon(nx,ny),stat=istatus) allocate(hterain(nx,ny),stat=istatus) allocate(hterain1(nx,ny),stat=istatus) allocate(hterain2(nx,ny),stat=istatus) allocate(hterout(nx,ny),stat=istatus) allocate(work(nx,ny),stat=istatus) allocate(iloc(nx,ny),jloc(nx,ny),stat=istatus) ! allocate(xs_ext(nx_ext),ys_ext(ny_ext),stat=istatus) allocate(terext(nx_ext,ny_ext),stat=istatus) allocate(dxfld(nx_ext),stat=istatus) allocate(dyfld(ny_ext),stat=istatus) allocate(rdxfld(nx_ext),stat=istatus) allocate(rdyfld(ny_ext),stat=istatus) allocate(slopey(nx_ext,ny_ext),stat=istatus) allocate(alphay(nx_ext,ny_ext),stat=istatus) allocate(betay(nx_ext,ny_ext),stat=istatus) allocate(iw(nx,ny),stat=istatus) ! !----------------------------------------------------------------------- ! ! Read in external terrain data ! !----------------------------------------------------------------------- ! lenstr = LEN(terndta_ext) CALL strlnth( terndta_ext, lenstr) mapproj=-1 ! CALL rdtrnall( nx_ext,ny_ext,dx_ext,dy_ext, & iproj_ext,trulat1_ext,trulat2_ext, & trulon_ext,scale_ext, & ctrlat_ext,ctrlon_ext, & terndta_ext(1:lenstr), terext) IF( scale_ext == 0.0 ) scale_ext = 1.0 ! IF(ctrlon_ext > 180.) ctrlon_ext=ctrlon_ext-360. IF(trulon_ext > 180.) trulon_ext=trulon_ext-360. ! !----------------------------------------------------------------------- ! ! Read in fine-scale terrain data ! !----------------------------------------------------------------------- ! lenstr = LEN(terndta) CALL strlnth( terndta, lenstr) mapproj=-1 ! CALL rdtrnall( nx,ny,dx,dy, & mapproj,trulat1,trulat2,trulon,sclfct, & ctrlat,ctrlon, & terndta(1:lenstr), hterain ) IF( sclfct == 0.0 ) sclfct = 1.0 ! IF(ctrlon > 180.) ctrlon=ctrlon-360. IF(trulon > 180.) trulon=trulon-360. latnot(1)=trulat1 latnot(2)=trulat2 CALL setmapr(mapproj,sclfct,latnot,trulon) ! CALL lltoxy(1,1,ctrlat,ctrlon,xctr,yctr) x0=xctr - 0.5*(nx-3)*dx y0=yctr - 0.5*(ny-3)*dy ! DO i=1,nx xs(i)=x0+(i-1)*dx END DO DO j=1,ny ys(j)=y0+(j-1)*dy END DO ! CALL xytoll(nx,ny,xs,ys,lat,lon) ! !----------------------------------------------------------------------- ! ! Interpolate the external data to the fine-scale grid ! !----------------------------------------------------------------------- ! latnot(1)=trulat1_ext latnot(2)=trulat2_ext CALL setmapr(iproj_ext,scale_ext,latnot,trulon_ext) CALL lltoxy(1,1,ctrlat_ext,ctrlon_ext,xctr,yctr) x0_ext=xctr - 0.5*(nx_ext-3)*dx_ext y0_ext=yctr - 0.5*(ny_ext-3)*dy_ext ! !----------------------------------------------------------------------- ! ! Set up external grid ! !----------------------------------------------------------------------- ! DO i=1,nx_ext xs_ext(i)=x0_ext+(i-1)*dx_ext END DO DO j=1,ny_ext ys_ext(j)=y0_ext+(j-1)*dy_ext END DO ! !----------------------------------------------------------------------- ! ! Find x,y locations of ARPS scalar grid in terms of the ! external grid. ! !----------------------------------------------------------------------- ! CALL lltoxy(nx,ny,lat,lon,xgr,ygr) ! !----------------------------------------------------------------------- ! ! Find i,j indices in the external data of the fine grid points ! !----------------------------------------------------------------------- ! CALL setijloc(nx,ny,nx_ext,ny_ext,xgr,ygr,xs_ext,ys_ext, & iloc,jloc) CALL setdxdy(nx_ext,ny_ext, & 1,nx_ext,1,ny_ext, & xs_ext,ys_ext,dxfld,dyfld,rdxfld,rdyfld) korder=MIN(iorder,2) CALL fldint2d(nx,ny,nx_ext,ny_ext, & 1,nx,1,ny, & 1,nx_ext,1,ny_ext, & korder,xgr,ygr,terext,xs_ext,ys_ext,iloc,jloc, & dxfld,dyfld,rdxfld,rdyfld, & slopey,alphay,betay, & hterain1) ! !----------------------------------------------------------------------- ! ! Correct for any bias in the external data ! This is to avoid artifical hills in the terrain due to ! any bias in the external data ! !----------------------------------------------------------------------- ! IF(rmvbias > 0) THEN sum=0. sum_ext=0. DO j=1,ny-1 DO i=1,nx-1 sum=sum+hterain(i,j) sum_ext=sum_ext+hterain1(i,j) END DO END DO bias=(sum_ext-sum)/FLOAT((nx-1)*(ny-1)) WRITE(6,'(/a,f6.2,a/)') ' Removing bias of ',bias,' meters' ! DO j=1,ny-1 DO i=1,nx-1 hterain1(i,j)=hterain1(i,j)-bias END DO END DO ELSE WRITE(6,'(/a,i4,a/)') & ' rmvbias= ',rmvbias,' --skipping bias removal.' END IF ! !----------------------------------------------------------------------- ! ! Blend the two terrain arrays ! !----------------------------------------------------------------------- ! ! scalex=-dx*dx/(rlen*rlen) ! scaley=-dy*dy/(rlen*rlen) scalex=dx/rlen scaley=dy/rlen WRITE(6,'(/a,f10.2)') & ' Merging terrain fields using length scale',rlen WRITE(6,'(a,f10.2,a)') & ' Which is equal to ',(1./scalex),' grid lengths in x' WRITE(6,'(a,f10.2,a/)') & ' and is equal to ',(1./scaley),' grid lengths in y' istart=iborder+1 iend=(nx-1)-iborder jstart=jborder+1 jend=(ny-1)-jborder ! ! Start with all points set to external terrain height ! DO j=1,ny-1 DO i=1,nx-1 hterain2(i,j) = hterain1(i,j) END DO END DO ! DO j=jstart,jend DO i=istart,iend ! w1=exp((i-1)*(i-1)*scalex) ! w2=exp((nx-1-i)*(nx-1-i)*scalex) ! w3=exp((j-1)*(j-1)*scaley) ! w4=exp((ny-1-j)*(ny-1-j)*scaley) ! wt=amin1(1.0,amax1(0.0,w1,w2,w3,w4)) ! hterain2(i,j) = (1.0-wt)*hterain(i,j) + wt*hterain1(i,j) w1=(i-istart)*scalex w2=(iend-i)*scalex w3=(j-jstart)*scaley w4=(jend-j)*scaley wt=AMAX1(0.0,AMIN1(1.0,w1,w2,w3,w4)) hterain2(i,j) = wt*hterain(i,j) + (1.-wt)*hterain1(i,j) END DO END DO ! !----------------------------------------------------------------------- ! ! Call edgehammer to filter noise near the edges caused ! by merging ! !----------------------------------------------------------------------- ! IF(nsmth > 0) THEN ksmth=MAX((nsmth/4),4) WRITE(6,'(/a)') ' Calling edge hammer' WRITE(6,'(a,i4,a,i4,a//)') & ' nsmth= ',nsmth,' affecting ',ksmth,' points from boundary' CALL edgeham(nx,ny,hterain2,work,hterout,nsmth,sm) ELSE WRITE(6,'(a)') ' nsmth= ',nsmth,' --skipping edge hammer.' DO j=1,ny-1 DO i=1,nx-1 hterout(i,j) = hterain2(i,j) END DO END DO END IF ! !----------------------------------------------------------------------- ! ! Write the final terrain field ! !----------------------------------------------------------------------- ! ternfn = terndta(1:lenstr)//'.new' lenstr = lenstr+4 terndmp = 1 CALL fnversn(ternfn, lenstr) CALL writtrn(nx,ny,ternfn(1:lenstr),dx,dy, & mapproj,trulat1,trulat2,trulon,sclfct, & ctrlat,ctrlon,hterout) ! !----------------------------------------------------------------------- ! ! Whip up some plots ! !----------------------------------------------------------------------- ! CALL xdevic CALL xdspac(0.9) CALL xafstyl(1) CALL xartyp(2) angl = 0.0 CALL xspace(nxpic, nypic, angl , xlimit,ylimit) CALL xaxfmt( '(i10)' ) CALL xpmagn(0.10*xlimit, 0.10*ylimit) ! !----------------------------------------------------------------------- ! ! Set map ! !----------------------------------------------------------------------- ! xl = (nx-3)*dx * 0.001 yl = (ny-3)*dy * 0.001 xorig = 0.0 yorig = 0.0 CALL xstpjgrd(mapproj,trulat1,trulat2,trulon, & ctrlat,ctrlon,xl,yl,xorig,yorig) DO j=1,ny DO i=1,nx xgr(i,j)=(i-1)*dx * 0.001 ygr(i,j)=(j-1)*dy * 0.001 END DO END DO DO iplt=1,3 CALL xnwpic xl = (nx-3)*dx * 0.001 yl = (ny-3)*dy * 0.001 xymax=AMAX1(xl,yl) CALL xmap(0.0,xymax, 0.0, xymax) CALL xaxsca(0.0,xl, (dx*0.001), 0.0, yl, (dy*0.001) ) cl(1)=0.0 cl(2)=50. CALL xnctrs(10,30) mode=1 IF(iplt == 1) THEN CALL xconta(hterain(2,2),xgr(2,2),ygr(2,2),iw,nx,nx-3,ny-3, & cl, ncl,mode ) ELSE IF (iplt == 2) THEN CALL xconta(hterain2(2,2),xgr(2,2),ygr(2,2),iw,nx,nx-3,ny-3, & cl, ncl,mode ) ELSE IF (iplt == 3) THEN CALL xconta(hterout(2,2),xgr(2,2),ygr(2,2),iw,nx,nx-3,ny-3, & cl, ncl,mode ) END IF IF(ovrmap == 1) THEN CALL xdrawmap(10,mapfile,mapgrid,latgrid,longrid) END IF END DO CALL xgrend STOP ! 600 CONTINUE PRINT *, ' Error reading input data, stopping' STOP ! END PROGRAM mrgtrn ! SUBROUTINE edgeham(nx,ny,hterain,work,newtern,nsmth,sm) 1 ! !----------------------------------------------------------------------- ! ! PURPOSE: ! !----------------------------------------------------------------------- ! ! AUTHOR: Keith Brewster ! 01/03/95 ! ! MODIFICATION HISTORY: ! !----------------------------------------------------------------------- ! ! INPUT: ! ! !----------------------------------------------------------------------- ! ! Variable Declarations. ! !----------------------------------------------------------------------- ! IMPLICIT NONE ! INTEGER :: nx,ny REAL :: hterain(nx,ny) REAL :: work(nx,ny) REAL :: newtern(nx,ny) INTEGER :: nsmth REAL :: sm ! !----------------------------------------------------------------------- ! ! Misc. local variables ! !----------------------------------------------------------------------- ! INTEGER :: i,j,ksm,kwid REAL :: wcen,wsid ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! DO j=1,ny-1 DO i=1,nx-1 newtern(i,j)=hterain(i,j) END DO END DO ! wcen=1.-sm wsid=0.5*sm DO ksm=nsmth,1,-1 kwid=ksm/4 kwid=MAX(kwid,4) DO j=1,ny-1 DO i=1,nx-1 work(i,j)=newtern(i,j) END DO END DO ! !----------------------------------------------------------------------- ! ! Smooth in the x direction near west boundary ! !----------------------------------------------------------------------- ! DO j=1,ny-1 DO i=2,kwid work(i,j)=wsid*(newtern(i-1,j)+newtern(i+1,j)) + & wcen* newtern(i,j) END DO END DO DO j=1,ny-1 work(1,j)=wsid*(newtern(1,j)+newtern(2,j)) + & wcen* newtern(1,j) END DO ! !----------------------------------------------------------------------- ! ! Smooth in the x direction near east boundary ! !----------------------------------------------------------------------- ! DO j=1,ny-1 DO i=(nx-kwid),nx-2 work(i,j)=wsid*(newtern(i-1,j)+newtern(i+1,j)) + & wcen* newtern(i,j) END DO END DO DO j=1,ny-1 work(nx-1,j)=wsid*(newtern(nx-1,j)+newtern(nx-2,j)) + & wcen* newtern(nx-1,j) END DO ! !----------------------------------------------------------------------- ! ! Smooth in the y direction near south boundary ! !----------------------------------------------------------------------- ! DO j=1,ny-1 DO i=1,nx-1 newtern(i,j)=work(i,j) END DO END DO DO j=2,kwid DO i=1,nx-1 newtern(i,j)=wsid*(work(i,j-1)+work(i,j+1)) + & wcen* work(i,j) END DO END DO DO i=1,nx-1 newtern(i,1)=wsid*(work(i,1)+work(i,2)) + & wcen* work(i,1) END DO ! !----------------------------------------------------------------------- ! ! Smooth in the y direction near north boundary ! !----------------------------------------------------------------------- ! DO j=(ny-kwid),ny-2 DO i=1,nx-1 newtern(i,j)=wsid*(work(i,j-1)+work(i,j+1)) + & wcen* work(i,j) END DO END DO DO i=1,nx-1 newtern(i,ny-1)=wsid*(work(i,ny-1)+work(i,ny-2)) + & wcen* work(i,ny-1) END DO END DO RETURN END SUBROUTINE edgeham ! !################################################################## !################################################################## !###### ###### !###### SUBROUTINE RDTRNALL ###### !###### ###### !###### Developed by ###### !###### Center for Analysis and Prediction of Storms ###### !###### University of Oklahoma ###### !###### ###### !################################################################## !################################################################## ! SUBROUTINE rdtrnall(nx,ny, dx,dy, & 2,4 mapproj,trulat1,trulat2,trulon,sclfct, & ctrlat,ctrlon, & terndta, hterain ) ! !----------------------------------------------------------------------- ! ! PURPOSE: ! ! Read the terrain data into model array hterain from a specified ! terrain data file. ! !----------------------------------------------------------------------- ! ! AUTHOR: Ming Xue ! 2/27/1994. ! ! 9/10/94 (Weygandt & Y. Lu) ! Cleaned up documentation. ! !----------------------------------------------------------------------- ! ! INPUT : ! ! nx Number of grid points in the x-direction (east/west) ! ny Number of grid points in the y-direction (north/south) ! ! dx Grid interval in x-direction ! dy Grid interval in y-direction ! ! terndta Terrain data file name ! ! OUTPUT: ! ! hterain Terrain height (m) ! !----------------------------------------------------------------------- ! ! !----------------------------------------------------------------------- ! ! Variable Declarations. ! !----------------------------------------------------------------------- ! IMPLICIT NONE INTEGER :: nx ! Number of grid points in the x-direction INTEGER :: ny ! Number of grid points in the y-direction REAL :: dx ! Grid interval in x-direction REAL :: dy ! Grid interval in y-direction INTEGER :: mapproj REAL :: trulat1 REAL :: trulat2 REAL :: trulon REAL :: sclfct REAL :: ctrlat REAL :: ctrlon CHARACTER (LEN=80) :: terndta ! Terrain data file name REAL :: hterain(nx,ny) ! Terrain height. ! !----------------------------------------------------------------------- ! ! Misc. local variables: ! !----------------------------------------------------------------------- ! INTEGER :: inunit,istat INTEGER :: nxin,nyin,idummy,ierr REAL :: dxin,dyin,rdummy,amin,amax !MP insert: character*80 savename !Message passing code. !MP insert: integer lenfl !Message passing code. !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! Beginning of executable code... ! !@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ! ! !----------------------------------------------------------------------- ! ! Define a uniform model grid. ! !----------------------------------------------------------------------- ! ! !----------------------------------------------------------------------- ! ! Read in the terrain data. ! !----------------------------------------------------------------------- ! CALL getunit( inunit ) !MP insert: lenfl = 80 !Message passing code. !MP insert: CALL strlnth( terndta, lenfl ) !Message passing code. !MP insert: savename(1:80) = terndta(1:80) !Message passing code. !MP insert: write(terndta, '(a,a,2i2.2)') !Message passing code. !MP insert: : savename(1:lenfl),'_',loc_x,loc_y CALL asnctl ('NEWLOCAL', 1, ierr) CALL asnfile(terndta, '-F f77 -N ieee', ierr) OPEN(UNIT=inunit,FILE=terndta,FORM='unformatted',STATUS='old', & IOSTAT=istat) !MP insert: terndta(1:80) = savename(1:80) !Message passing code. IF( istat /= 0) THEN WRITE(6,'(/1x,a,a,/1x,a/)') & 'Error occured when opening terrain data file ', & terndta,' Job stopped in READTRN.' STOP END IF READ(inunit,ERR=999) nxin,nyin IF((nx /= nxin).OR.(ny /= nyin))THEN WRITE(6,'(a,/a,i5,a,i5,/a,i5,a,i5)') & ' Array size in the terrain data does not match that of the', & ' model grid. Dimensions in the data were nx=',nxin, & ', ny=',nyin,' the model grid size were nx=',nx,' ny= ', ny WRITE(6,'(a)') ' Job stopped in subroutine READTRN.' STOP END IF READ(inunit,ERR=999) idummy,mapproj,idummy,idummy,idummy, & idummy,idummy,idummy,idummy,idummy, & idummy,idummy,idummy,idummy,idummy, & idummy,idummy,idummy,idummy,idummy READ(inunit,ERR=999) dxin ,dyin ,ctrlat,ctrlon,rdummy, & rdummy,trulat1,trulat2,trulon,sclfct, & rdummy,rdummy,rdummy,rdummy,rdummy, & rdummy,rdummy,rdummy,rdummy,rdummy IF(ABS((dx-dxin)/dx) > 0.01.OR.ABS((dy-dyin)/dy) > 0.01)THEN WRITE(6,'(a,a,/2(a,f13.4),/2(a,f13.4))') & 'Grid intervals in the terrain data do not match those ', & 'in the model.','In the data dx=',dxin,', dy=',dyin, & 'In the model dx=',dx,' dy= ', dy WRITE(6,'(a)') ' Job stopped in subroutine READTRN.' STOP END IF READ(inunit,ERR=999) hterain WRITE(6,'(1x,a/)') 'Minimum and maximum terrain height:' CALL a3dmax0(hterain,1,nx,1,nx-1, 1,ny,1,ny-1, 1,1,1,1,amax,amin) WRITE(6,'(1x,2(a,e13.6))') 'htrnmin = ', amin,', htrnmax=',amax RETURN 999 WRITE(6,'(1x,a)') & 'Error in reading terrain data. Job stopped in READTRN.' STOP END SUBROUTINE rdtrnall