!----------------------------------------------------------------------- ! !The attached program will process a file containing one or more soundings from !the FSL (GSD) online radiosonde database and translate the soundings into !file(s) that can be used in ADAS or 3DVAR. For files with multiple data !times, the soundings will be sorted by data time and output to the appropriate !file, each named according to the date and time. The program can also use a !station file to verify the station locations with the latest global station !list information from NOAA – use of this station file is optional. ! !You can get that file from http://weather.noaa.gov/data/nsd_cccc.gz ! !To set-up the program, just compile it with an f90 compiler. No other !libraries are required. ! !To use the program just start it and it will prompt for the name of the !ASCII file saved from the web download of the data from ! ! http://raob.fsl.noaa.gov ! !When using the web interface select “FSL Format (ASCII)” and wind units of !“kts” (the default selections). ! !To use the output in ADAS or ARPS 3DVAR put the name of the output file !in the section of the arps.input file that begins with nuafil, using the !variable uafname. ! !-Keith (05.24.2007) ! !----------------------------------------------------------------------- PROGRAM fsl2snd,2 ! ! Keith Brewster ! CAPS, University of Oklahoma ! May, 2007 ! IMPLICIT NONE ! ! Header data ! INTEGER :: lintyp INTEGER :: hour,day,year,minute CHARACTER(LEN=3) :: month INTEGER :: wban,wmo REAL :: rlat,rlon,selev INTEGER :: ielev,itime INTEGER :: hydro,mxwd,tropl,lines,tindex,source CHARACTER(LEN=4) :: staid INTEGER :: sonde CHARACTER(LEN=2) :: wsunits CHARACTER(LEN=1) :: ns,ew REAL, PARAMETER :: kts2ms=0.514444 REAL :: dtr,spcvt,dtdz,dtddz,dudz,dvdz REAL :: tempk,dewpk INTEGER :: iline,nlines,nlevs,i,j,k,imon,lunit,ntime INTEGER :: kbot,ktop,kk,kn INTEGER :: idata(6) LOGICAL :: fndtop,newtime INTEGER, PARAMETER :: maxtime=20 CHARACTER(LEN=126) :: fname CHARACTER(LEN=126) :: outsnd CHARACTER(LEN=12) :: timestr CHARACTER(LEN=12) :: filtime(maxtime) INTEGER :: filunit(maxtime) CHARACTER(LEN=3) :: chmon(12) = & (/'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'/) ! ! Output data ! INTEGER, parameter :: maxlev=400 REAL :: press(maxlev) REAL :: height(maxlev) REAL :: temp(maxlev) REAL :: dewpt(maxlev) REAL :: wdir(maxlev) REAL :: wspd(maxlev) REAL :: u(maxlev) REAL :: v(maxlev) ! ! Station data table variables ! INTEGER, PARAMETER :: maxtable=10000 CHARACTER (LEN=180) :: statbl(maxtable) CHARACTER (LEN=4) :: staidtbl(maxtable) INTEGER :: wmotbl(maxtable) INTEGER, PARAMETER :: maxsemi=100 INTEGER :: slocs(maxsemi) CHARACTER(LEN=1) :: cdir REAL :: slat,slon INTEGER :: ilat1,ilat2,ilat3,ilon1,ilon2,ilon3 INTEGER :: ista,jsta,nsta,istat,wmogrp,wmosta,nsemi LOGICAL :: EOF ! nsta=0 minute=0 EOF=.false. dtr=atan(1.)/45. DO itime=1,maxtime filunit(itime)=20+itime END DO ! print *, ' Opening NOAA station list file' OPEN(19,file='nsd_cccc',iostat=istat,status='old') IF(istat == 0) THEN EOF=.false. DO jsta=1,maxtable READ(19,'(a180)',iostat=istat) statbl(jsta) IF(istat < 0 ) EOF = .true. IF(istat /= 0 ) EXIT staidtbl(jsta)=statbl(jsta)(1:4) READ(statbl(jsta)(6:11),'(i2,1x,i3)',iostat=istat) wmogrp,wmosta IF(istat == 0) THEN wmotbl(jsta)=(wmogrp*1000)+wmosta ELSE wmotbl(jsta)=-999 END IF ! print *, ' jsta: ',jsta,' id:',staidtbl(jsta),' wmo:',wmotbl(jsta) END DO nsta=jsta-1 IF(EOF) THEN WRITE(6,'(a)') ' End of file reached' ELSE WRITE(6,'(a/a,i6)') & ' Error before end of file or ran out of allocated space', & ' Space allocated is',maxtable END IF WRITE(6,'(a,i6,a)') ' Read',nsta,' stations from NOAA file' CLOSE(19) ELSE nsta=0 WRITE(6,'(a)') ' Error opening NOAA station table file, nsd_cccc' WRITE(6,'(a)') ' Obtain file from' WRITE(6,'(a)') ' http://weather.noaa.gov/data/nsd_cccc.gz' WRITE(6,'(a)') ' and uncompress it.' WRITE(6,'(a)') ' Meanwhile, continuing using FSL assigned lat,lons' END IF ! write(6,'(a)') ' Input data file name' read(5,'(a126)') fname write(6,'(a,a)') 'Opening ',fname open(11,file=fname,status='old') DO ista=1,99999 ! ! Read header lines ! read(11,'(3i7,6x,a3,i8)',iostat=istat) lintyp,hour,day,month,year IF(istat /= 0) EXIT read(11,'(3i7,f7.2,a1,f6.2,a1,i6,i7)',iostat=istat) & lintyp,wban,wmo,rlat,ns,rlon,ew,ielev,itime IF(istat /= 0) EXIT read(11,'(7i7)',iostat=istat) lintyp,hydro,mxwd,tropl,lines,tindex,source IF(istat /= 0) EXIT read(11,'(i7,10x,a4,14x,i7,5x,a2)',iostat=istat) lintyp,staid,sonde,wsunits IF(istat /= 0) EXIT IF(wsunits.eq.'kt') THEN spcvt=kts2ms ELSE spcvt=1.0 END IF IF(ns .eq. 'S') rlat=-rlat IF(ew .eq. 'W') rlon=-rlon selev=float(ielev) DO imon=1,11 IF(chmon(imon) == month) EXIT END DO ! ! Open output file ! write(timestr,'(i4.4,i2.2,i2.2,i2.2,i2.2)') year,imon,day,hour,minute IF(ista == 1) THEN write(outsnd,'(a,a,a)') 'raobfsl',timestr,'.snd' filtime(1)=timestr lunit=filunit(1) open(lunit,file=outsnd,status='unknown') ntime=1 ELSE newtime=.true. DO itime=1,ntime IF(filtime(itime) == timestr) THEN newtime=.false. lunit=filunit(itime) EXIT END IF END DO IF(newtime) THEN IF(ntime < maxtime) THEN ntime=ntime+1 lunit=filunit(ntime) filtime(ntime)=timestr write(outsnd,'(a,a,a)') 'raobfsl',timestr,'.snd' open(lunit,file=outsnd,status='unknown') ELSE write(6,'(a,i4,a,i4)') ' Ntime',(ntime+1),' exceeds maxtime',maxtime EXIT END IF END IF END IF ! ! Get more precise station location info from the data table ! slat=-999. slon=-999. print *, ' Searching loc table for ',staid,wmo DO jsta=1,nsta IF((staidtbl(jsta) == staid) .OR. (wmotbl(jsta) == wmo)) THEN print *, ' Found match at ',jsta print *, ' Table values: ',staidtbl(jsta),wmotbl(jsta) CALL semilocs(maxsemi,statbl(jsta),nsemi,slocs) print *, ' nsemi=',nsemi ilat3=0 cdir='N' IF((slocs(8)-slocs(7)) > 8) THEN READ(statbl(jsta)((slocs(7)+1):(slocs(7)+9)),'(i2,1x,i2,1x,i2,a1)',iostat=istat) & ilat1,ilat2,ilat3,cdir print *, 'Lat read2: ',ilat1,ilat2,istat IF(istat /= 0) EXIT ELSE READ(statbl(jsta)((slocs(7)+1):(slocs(7)+6)),'(i2,1x,i2,a1)',iostat=istat) & ilat1,ilat2,cdir print *, 'Lat read2: ',ilat1,ilat2,istat IF(istat /= 0) EXIT END IF slat=float(ilat1)+(float(ilat2)/60.)+(float(ilat3)/3600.) IF(cdir == 'S') slat=-slat ilon3=0 cdir='W' IF((slocs(9)-slocs(8)) > 9) THEN READ(statbl(jsta)((slocs(8)+1):(slocs(8)+10)),'(i3,1x,i2,1x,i2,a1)',iostat=istat) & ilon1,ilon2,ilon3,cdir print *, 'Lon read1: ',ilon1,ilon2,istat IF(istat /= 0) EXIT ELSE READ(statbl(jsta)((slocs(8)+1):(slocs(8)+7)),'(i3,1x,i2,a1)',iostat=istat) & ilon1,ilon2,cdir print *, 'Lon read2: ',ilon1,ilon2,istat IF(istat /= 0) EXIT END IF slon=float(ilon1)+(float(ilon2)/60.)+(float(ilon3)/3600.) IF(cdir == 'W') slon=-slon EXIT END IF END DO print *, ' rlat: ',rlat,' rlon:',rlon print *, ' slat: ',slat,' slon:',slon IF(slat > -900.) rlat=slat IF(slon > -900.) rlon=slon ! ! Read Sonde data ! k=0 nlines=lines-4 DO iline=1,nlines read(11,'(7i7)',iostat=istat) lintyp,(idata(j),j=1,6) IF(istat /= 0) EXIT ! print *, lintyp,(idata(j),j=1,6) IF(idata(2).ge.ielev .AND. idata(2).lt.99990) THEN k=k+1 IF(idata(1).lt.99990) THEN press(k)=0.1*idata(1) ELSE press(k)=99999. END IF height(k)=float(idata(2)) IF(idata(3).lt.99990) THEN temp(k)=idata(3)*0.1 ELSE temp(k)=99999. END IF IF(idata(4).lt.9990) THEN dewpt(k)=idata(4)*0.1 ELSE dewpt(k)=99999. END IF IF(idata(5).lt.99990 .and. idata(6).lt.200) THEN wdir(k)=float(idata(5)) wspd(k)=spcvt*idata(6) u(k)=-wspd(k)*sin(dtr*wdir(k)) v(k)=-wspd(k)*cos(dtr*wdir(k)) ELSE u(k)=99999. v(k)=99999. END IF END IF END DO nlevs=k ! ! Interpolate missing temperatures ! DO k=2,nlevs IF(temp(k).gt.50.) THEN kbot=k-1 fndtop=.false. DO kn=k+1,nlevs IF(temp(kn).le.50.) THEN fndtop=.true. ktop=kn EXIT END IF END DO IF(fndtop) THEN dtdz=(temp(ktop)-temp(kbot))/ & (height(ktop)-height(kbot)) DO kk=k,ktop-1 temp(kk)=temp(kbot)+dtdz*(height(kk)-height(kbot)) END DO ELSE EXIT END IF END IF END DO ! ! Interpolate missing dew points ! DO k=2,nlevs IF(dewpt(k).gt.40.) THEN kbot=k-1 fndtop=.false. DO kn=k+1,nlevs IF(dewpt(kn).le.40.) THEN fndtop=.true. ktop=kn EXIT END IF END DO IF(fndtop) THEN dtddz=(dewpt(ktop)-dewpt(kbot))/ & (height(ktop)-height(kbot)) DO kk=k,ktop-1 dewpt(kk)=dewpt(kbot)+dtddz*(height(kk)-height(kbot)) END DO ELSE EXIT END IF END IF END DO ! ! Interpolate missing winds ! DO k=2,nlevs IF(u(k).gt.300.) THEN kbot=k-1 fndtop=.false. DO kn=k+1,nlevs IF(u(kn).le.300.) THEN fndtop=.true. ktop=kn EXIT END IF END DO IF(fndtop) THEN dudz=(u(ktop)-u(kbot))/ & (height(ktop)-height(kbot)) dvdz=(v(ktop)-v(kbot))/ & (height(ktop)-height(kbot)) DO kk=k,ktop-1 u(kk)=u(kbot)+dudz*(height(kk)-height(kbot)) v(kk)=v(kbot)+dvdz*(height(kk)-height(kbot)) CALL get_ddff(u(kk),v(kk),wdir(kk),wspd(kk)) END DO ELSE EXIT END IF END IF END DO ! ! Write sounding ! Note radiosonde dewpts are always wrt liquid. ! write(lunit,'(i12,i12,f11.4,f15.4,f15.0,5x,a4)') & wmo,nlevs,rlat,rlon,selev,staid DO k = 1,nlevs write(lunit,'(f10.1,3f10.2,f10.1,f10.2)') & height(k),press(k),temp(k),dewpt(k),wdir(k),wspd(k) END DO END DO ! big station loop DO itime=1,ntime CLOSE(filunit(itime)) END DO WRITE(6,'(a,i5,a,i4,a)') & ' Processed ',(ista-1),' sounding(s) at ',ntime,' separate time(s)' WRITE(6,'(a)') ' fsl2snd successful completion' STOP END PROGRAM fsl2snd ! SUBROUTINE semilocs(maxsemi,string,nsemi,slocs) 1 ! ! Parse a string and report the location of all semi-colons ! Keith Brewster, CAPS ! IMPLICIT NONE INTEGER :: maxsemi CHARACTER (LEN=*) string INTEGER :: nsemi INTEGER :: slocs(maxsemi) INTEGER :: iloc,i INTEGER :: slen nsemi=0 DO iloc=1,maxsemi slocs(iloc)=-99 END DO slen=LEN(TRIM(string)) DO i=1,slen IF(string(i:i) == ';') THEN nsemi=nsemi+1 slocs(nsemi)=i END IF END DO END SUBROUTINE semilocs ! SUBROUTINE GET_DDFF(U,V,DD,FF) 5 IMPLICIT NONE REAL :: U,V,DD,FF REAL, PARAMETER :: RAD2D=57.29577951 REAL, PARAMETER :: SPVAL=9999. REAL, PARAMETER :: MIS_VAL=99999.0 IF(U.LT.SPVAL .AND. V.LT.SPVAL) THEN FF = SQRT((U*U + V*V)) IF(FF.NE.0.) THEN DD = RAD2D*ATAN2(U,V) DD = DD+180. IF (DD.GT.360.) DD=DD-360. ELSE DD=0. END IF ELSE DD = MIS_VAL FF = MIS_VAL END IF RETURN END SUBROUTINE GET_DDFF