!-----------------------------------------------------------------------
!
!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