c ++++BEGIN ANNULAR HURRICANE INDEX MODULE++++ c c version 19.1.0 c c c This set of routines calculates the probability of a tropical c cyclone becoming an annular cyclone in the next 24h. They were c adapted to be cut and pasted into the SHIPS model and run in c realtime. c-----7---------------------------------------------------------------72 SUBROUTINE id_annular_op(luout,stname,tcfid,fn_ships,fn_ird1, . fn_ird2,fn_iri1,fn_iri2,ilmon,ilday, . iyr,iltime,dfval,ann_prob,ahi_sst) c-----7---------------------------------------------------------------72 c id_annular_op.f determines the probability of a tropical c cyclone becoming an annular cyclone within 24 h. It uses the most c recent SHIPS run and requires at least 1 IR data file within 12h c of the SHIPS data file, but ideally uses 2 IR data files. c c c Operational version of id_annular.test3.f written by Thomas Cram, c CIRA/CSU, February 2006 c c Adapted from McIDAS GOES-IR AREA file reader program written c by Jim Kossin, CIRA/CSU, Jan. 2002 c c Input: c luout = unit number for writing data output c stname = storm name, 10 character string c tcfid = ATCF storm id, 8 character string c fn_ships = SHIPS data file name - eg. 'lsdiag.dat' c fn_ird1 = IR data file name - eg. 'IRRP1.dat' c fn_ird2 = IR data file name - eg. 'IRRP2.dat' c fn_iri1 = IR information file name - eg. 'IRRP1.inf' c fn_iri2 = IR information file name - eg. 'IRRP2.inf' c ahi_sst = real sst array(0:mft) with AHI sst for all forecast times c the SST is the same as used by SHIPS model, but J Cione c cooling is NOT applied. The selections of SST from climo and c observed,and different types of SST is done in iships.f c c Output: c ilmon = storm month from SHIPS file, eg. '09' for Sep c ilday = storm day from SHIPS file, eg. '23' for the 23rd c iyr = storm year from SHIPS file, eg. '2005' c iltime = storm time from SHIPS file, UTC, eg '0600' c dfval = discriminant function value normalized to c vary between 0 and 1 = annular hurr index c ann_prob = probability of annular structure c c c Should be machine independent (portable) assuming that: c 1) The RECL specifiers in the OPEN statements refer to bytes, c not words. c 2) The default size of integers is 4 bytes. c c REQUIRES SUBROUTINES: c read_ships c ir_prof_avg2 c detend - removed (KM) c read_radprof c moment c chartointmon c ahindex c tdiff c c Modified by Andrea Schumacher for operational use, CIRA, July 2006 c c MODIFIED: February 16, 2007 - JAK c 1) changed the number of disciminants used to 5 c 2) more changes to ahindex and block data. c c Modified by Stephanie Stevenson, April 2020 c Changed mft and lsdiag reading for 7day input c c-----7---------------------------------------------------------------72 parameter(maxavg=1000) ! max size of 1D radial profile arrays parameter(radmax=600.) ! max radius of profile output files parameter(maxrad=radmax/4) ! max number of elements in profiles dimension raz(maxrad) character *10 stname character*9 stnm ! storm name character*9 stnmabr ! abbreviated storm name character*8 tcfid character*2 bas ! ocean basin (AT,EP,WP,SP,CP,NI,SI) real xmsng character*3 irmonchar character*40 errmsg0,errmsg1,errmsg2,errmsg3,errmsg4,errmsg5 c Averaged IR data real prof_avg(maxrad),std_avg(maxrad) integer irerr,irerr1,irerr2,irerrflg integer ibuff integer useir1,useir2 c Annular hurricane predictors real std_cpix,eye_diff real cpix,std,var,weye,shrd,shrs,shrg,u200,t200,vmax ! Other screening variables real gen_sst real mmaxval c SHIPS data parameter(mft=28) integer ilyr,ilmon,ilday,iltime,ivmx,iyr integer ishrd(0:mft),ishtd(0:mft),ishrs(0:mft),ishts(0:mft), + ishrg(0:mft),iu200(0:mft),it200(0:mft), + irefc(0:mft),ivmax(0:mft) c this SST is passed from iships. It's the same SST as used by SHIPS c model, with the selection feom climo, observed, and various available c SST datasets. However, J Cione cooling is NOT used for AHI real ahi_sst(0:mft) integer endoffile integer ludiag character*4 sname4 character*34 fn_ships character*34 fn_ird1 character*34 fn_ird2 character*34 fn_iri1 character*34 fn_iri2 integer iphold,irhold real tbmin,tbmax integer smiss ! SHIPS missing data value (=9999) c Array counters integer sample_count integer luout real dv,dfval,ann_prob integer screen_fail logical radexist c-----7---------------------------------------------------------------72 ! Standardized data real weye_s, var_s, std_s, sst_s, u200_s c-----7---------------------------------------------------------------72 ! Statistical moments and discriminant weights (block data) REAL sdev(5),means(5),dweights(5),div common /MOMENTS/ sdev,means common /DWEIGHTS/ dweights common /DIVIDER/ div c-----7---------------------------------------------------------------72 c actual lag in days of the observed SST c irlag - WSST c irdllag - daily c iohclag - daily observed OHC integer irlag,irdllag,iohclag,iobslag c c Set ishort=1 for short form of output for SHIPS text file ishort=1 c Specify total number of screening variables for output nscreen=7 c ludiag=50 xmsng=-1.0 endoffile=0 sample_count=0 ibuff=0 ! SHIPS missing data value smiss=9999 ! Discriminant value missing data dmiss=9999. ir1ex=0 ir2ex=0 irex=0 ir1tg=0 ir2tg=0 irtg=0 ivmx=0 dv=0.0 dfval=0.0 ann_prob=0.0 c write(errmsg0,631) 'NOTE:',', ANNULAR INDEX RAN NORMALLY' errmsg0=' ANNULAR INDEX RAN NORMALLY' write(errmsg1,632) 'ERR=1',', SHIPS FILE MISSING' write(errmsg2,633) 'ERR=2',', BOTH IR FILES BAD OR MISSING' write(errmsg3,634) 'ERR=3',', IR & SHIPS DATA > 12h APART' write(errmsg4,635) 'ERR=4',', SHIPS DATA MISSING' errmsg5='NOTE: 1 INSTEAD OF 2 GOES FILES USED' c write(errmsg5,636) c636 format(5x,'NOTE: 1 INSTEAD OF 2 GOES FILES USED ') c637 format(/,/,/,/,a40) 637 format(' ##',4x,a40) 638 format(' ##',4x,a40) 639 format(' ##',4x,a40) c639 format(/,13x,a40) 631 format(5x,a5,a28,2x) 632 format(5x,a5,a20,10x) 633 format(5x,a5,a30) 634 format(5x,a5,a29,1x) 635 format(5x,a5,a20,10x) mmaxval=-3.105263 c-----7---------------------------------------------------------------72 c open data output file c c open(unit=luout,file='./annout.dat',status='replace') c c c open warning message file c c open(unit=luwarn,file='./warning_msg2.out',status='unknown') c c c determine endian-ness of host machine c c call detend(indwrd) c-----7---------------------------------------------------------------72 c Verify that SHIPS data file exists. If not, fail. If so, read header. c-----7---------------------------------------------------------------72 ! Open SHIPS file on first pass open(unit=ludiag,file=fn_ships,status='old',err=901) !Read the date and time info from SHIPS data file c read(ludiag,110,err=901,end=901) sname4,ilyr,ilmon,ilday, c + iltime,ivmx,iheader c 110 format(1x,a4,1x,3(i2.2),1x,i2.2,1x,i4,a110) read(ludiag,110,err=901,end=901) sname4,ilyr,ilmon,ilday, + iltime,ivmx 110 format(1x,a4,1x,3(i2.2),1x,i2.2,1x,i4) close(ludiag) c-----7---------------------------------------------------------------72 c c Write header to output file, first calculating 4-digit year: c c-----7---------------------------------------------------------------72 if (ilyr.lt.40) then iyr=2000+ilyr write(stnm,25) sname4(1:3) write(stnmabr,26) ilyr,bas,sname4(1:3) else iyr=1900+ilyr write(stnm,25) sname4(1:3) write(stnmabr,28) ilyr,bas,sname4(1:3) endif 25 format(a3) 26 format('20',i2.2,a2,a3) 28 format('19',i2.2,a2,a3) c write(luout,600) tcfid,stname,ilmon,ilday, + ilyr,iltime 600 format(/,' ##',9x,'ANNULAR HURRICANE INDEX (AHI) ',a8,1x,a10, + 1x,i2.2,'/',i2.2,'/',i2.2,2x,i2.2,' UTC ##') c-----7---------------------------------------------------------------72 c Verify 1st .inf and .dat files both exist. If so, read header and c determine if .dat file time is > 12h from SHIPS data file time. c-----7---------------------------------------------------------------72 ! Does IR radial profile file exist? inquire(file=fn_ird1,exist=radexist) ir1ex=0 if(radexist) then open(unit=ludiag+2,file=fn_iri1,status='old',err=902) read(unit=ludiag+2,fmt=111,err=902,end=902) irday, + irmonchar,iryr,irtime 111 format(/,/,/,/,1x,i2.2,2x,a3,4x,i2,1x,i2) ir1ex=1 call chartointmon(irmonchar,irmon) call tdiff(iryr,irmon,irday,irtime,ilyr,ilmon,ilday,iltime, + idelt) if (idelt.gt.12.or.idelt.lt.-12) then ir1tg=0 else ir1tg=1 endif 902 endif close(ludiag+2) c-----7---------------------------------------------------------------72 c Verify 2nd .inf and .dat files both exist. If so, read header and c determine if .dat file time is > 12h from SHIPS data file time. c-----7---------------------------------------------------------------72 ! Does IR radial profile file exist? inquire(file=fn_ird2,exist=radexist) ir2ex=0 if(radexist) then open(unit=ludiag+2,file=fn_iri2,status='old',err=903) read(unit=ludiag+2,fmt=112,err=903,end=903) irday, + irmonchar,iryr,irtime 112 format(/,/,/,/,1x,i2.2,2x,a3,4x,i2,1x,i2) ir2ex=1 call chartointmon(irmonchar,irmon) call tdiff(iryr,irmon,irday,irtime,ilyr,ilmon,ilday,iltime, + idelt) if (idelt.gt.12.or.idelt.lt.-12) then ir2tg=0 else ir2tg=1 endif 903 endif close(ludiag+2) irex = ir1ex+ir2ex irtg = ir1tg+ir2tg ! If both IR files are missing, display error in data output ! file and skip to the end (ie, calculation fails) if (irex.eq.0) then write(luout,638) errmsg2 return endif ! If both IR files are more than 12h before or after the ! current SHIPS data, display error in data output file ! and skip to the end (ie, calcualtion fails) if (irtg.eq.0) then write(luout,638) errmsg3 return endif if ((ir1ex.eq.1).and.(ir1tg.eq.1)) then useir1 = 1 else useir1 = 0 endif if ((ir2ex.eq.1).and.(ir2tg.eq.1)) then useir2 = 1 else useir2 = 0 endif c-----7---------------------------------------------------------------72 c Open and Read in SHIPS data c-----7---------------------------------------------------------------72 ! Open SHIPS file open(unit=ludiag,file=fn_ships,status='old',err=901) 5 call read_ships(ludiag,sname4,ilyr,ilmon,ilday,iltime,ivmx, + iu200,it200, + irefc,ishrd,ishtd,ishrs, + ishts,ishrg,endoffile) c-----7---------------------------------------------------------------72 c Call routine 'ir_prof_avg2' to read in IR Tb radial profiles, c compute the Tb standard deviations, and then compute average radial c profiles of each. c-----7---------------------------------------------------------------72 call ir_prof_avg2(fn_ird1,fn_ird2,fn_iri1,fn_iri2, + iyr,useir1,useir2,prof_avg,std_avg, + raz,ibuff,irerr) if (sum(prof_avg).le.0) then dv=dmiss dfval=dmiss ann_prob=0.0 write(luout,638) errmsg2 return endif c-----7---------------------------------------------------------------72 c Screen SHIPS data -- skip if environmental conditions would not c support an annular hurricane c-----7---------------------------------------------------------------72 screen_fail = 0 ahi = 0.0 c vmxr = float(ivmx) if (ivmx .lt. 85) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,652) vmxr 652 format(5x,'SCREENING STORM INTENSITY = ',f6.1, + ' kt > 84 kt? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,653) vmxr 653 format(5x,'SCREENING STORM INTENSITY = ',f6.1, + ' kt > 84 kt? ---> PASSED') endif endif rsstr = ahi_sst(0) if (rsstr .lt. 24.3) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,654) rsstr 654 format(5x,'SCREENING SST = ',f6.1, + ' C > 24.3 C ? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,655) rsstr 655 format(5x,'SCREENING SST = ',f6.1, + ' C > 24.3 C ? ---> PASSED') endif endif if (rsstr .gt. 29.1) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,656) rsstr 656 format(5x,'SCREENING SST = ',f6.1, + ' C < 29.1 C ? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,657) rsstr 657 format(5x,'SCREENING SST = ',f6.1, + ' C < 29.1 C ? ---> PASSED') endif endif c shrdr = 0.1*float(ishrd(0)) if (shrdr .gt. 22.0) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,658) shrdr 658 format(5x,'SCREENING VERT. SHR = ',f6.1, + ' kt < 22.0 kt? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,659) shrdr 659 format(5x,'SCREENING VERT. SHR = ',f6.1, + ' kt < 22.0 kt? ---> PASSED') endif endif u200r = 0.1*float(iu200(0)) if (u200r .lt. -23.0) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,662) u200r 662 format(5x,'SCREENING 200 hPa ZONAL WIND = ',f6.1, + ' kt > -23.0 kt? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,663) u200r 663 format(5x,'SCREENING 200 hPa ZONAL WIND = ',f6.1, + ' kt > -23.0 kt? ---> PASSED') endif endif if (u200r .gt. 3.0) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,664) u200r 664 format(5x,'SCREENING 200 hPa ZONAL WIND = ',f6.1, + ' kt < 3.0 kt? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,665) u200r 665 format(5x,'SCREENING 200 hPa ZONAL WIND = ',f6.1, + ' kt < 3.0 kt? ---> PASSED') endif endif refcr = 0.1*float(irefc(0)) if (refcr .lt. -9.0) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,666) refcr 666 format(5x,'SCREENING 200 hPa MOM FLUX CONV = ',f6.1, + ' m/s-day > -9.0 m/s-day? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,667) refcr 667 format(5x,'SCREENING 200 hPa MOM FLUX CONV = ',f6.1, + ' m/s-day > -9.0 m/s-day? ---> PASSED') endif endif if (refcr .gt. 11.0) then dv=dmiss dfval=dmiss ann_prob=0.0 screen_fail=screen_fail+1 if (ishort .ne. 1) then write(luout,668) refcr 668 format(5x,'SCREENING 200 hPa MOM FLUX CONV = ',f6.1, + ' m/s-day < 11.0 m/s-day? ---> FAILED') endif else if (ishort .ne. 1) then write(luout,669) refcr 669 format(5x,'SCREENING 200 hPa MOM FLUX CONV = ',f6.1, + ' m/s-day < 11.0 m/s-day? ---> PASSED') endif endif 702 format(5x,a27,i6,a13,13x,a11) 703 format(5x,a15,f6.1,a14,24x,a11) 704 format(5x,a21,f6.1,a16,16x,a11) 705 format(5x,a25,f6.1,a17,11x,a11) 706 format(5x,a26,f6.1,a25,2x,a11) 707 format(5x,a29,f6.1,a16,8x,a11) 712 format(19x,a35) 713 format(19x,a28) 714 format(19x,a44) 715 format(19x,a36) 716 format(19x,a41) c-----7---------------------------------------------------------------72 c Skip if missing data missdata_fail=0 if (ahi_sst(0).ge.dmiss-1) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (ishrd(0).eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (ishrs(0).eq.smiss) then dv=dmiss dfval=dmiss missdata_fail=missdata_fail+1 endif if (ishrg(0).eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (iu200(0).eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (it200(0).eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (irefc(0).eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (ivmx.eq.smiss) then dv=dmiss dfval=dmiss ann_prob=0.0 missdata_fail=missdata_fail+1 endif if (missdata_fail.gt.0) then write(luout,638) errmsg4 return endif c-----7---------------------------------------------------------------72 c c Find radius of coldest Tb pixel in averaged IR profile c and grab standard deviation at that radius c tbmin=1.e3 tbmax=-1. irhold=0 iphold=0 ! Determine size of prof_avg (i.e. where prof_avg does not ! contain missing data) do iprof=1,maxrad if (prof_avg(iprof).ne.xmsng) then iphold=iprof endif enddo ! Find radius of coldest pixel and std dev. do iprof=1,maxrad if ((prof_avg(iprof).lt.tbmin).and. + (prof_avg(iprof).ne.xmsng)) then tbmin=prof_avg(iprof) cpix=raz(iprof) std_cpix=std_avg(iprof) irhold=iprof endif enddo c-----7---------------------------------------------------------------72 c Skip if missing data if ((iphold.lt.2).or.(irhold.eq.0)) then dv=dmiss dfval=dmiss ann_prob=0.0 return endif if (std_cpix.lt.0) then dv=dmiss dfval=dmiss ann_prob=0.0 return endif c-----7---------------------------------------------------------------72 c Calculate variance of radial profile c call moment(prof_avg(1:iphold),iphold,ave_prof,adev_prof, + sdev_prof,var_prof,skew_prof,curt_prof) c c Calculate warm eye - cold ring difference c do iprof=1,irhold if (prof_avg(iprof).gt.tbmax) then tbmax=prof_avg(iprof) eye_diff=tbmax-tbmin endif enddo c-----7---------------------------------------------------------------72 c Screen IR data -- skip if cold eye exists if (cpix .lt. 50.) then dv=dmiss dfval=dmiss ann_prob=0.0 if (ishort .ne. 1) then write(luout,670) cpix 670 format(5x,'SCREENING GOES RAD COLD BR TEMP = ',f6.1, + ' km > 50.0 km? ---> FAILED') endif screen_fail=screen_fail+1 else if (ishort .ne. 1) then write(luout,671) cpix 671 format(5x,'SCREENING GOES RAD COLD BR TEMP = ',f6.1, + ' km > 50.0 km? ---> PASSED') endif endif if (eye_diff .lt. 15.) then dv=dmiss dfval=dmiss ann_prob=0.0 if (ishort .ne. 1) then write(luout,672) eye_diff 672 format(5x,'SCREENING GOES EYE-RING BR TEMP = ',f6.1, + ' C > 15.0 C ? ---> FAILED') endif screen_fail=screen_fail+1 else if (ishort .ne. 1) then write(luout,673) eye_diff 673 format(5x,'SCREENING GOES EYE-RING BR TEMP = ',f6.1, + ' C > 15.0 C ? ---> PASSED') endif endif if (screen_fail.gt.0) then if (ishort .eq. 1) then nfail = screen_fail npass = nscreen-nfail write(luout,780) npass,nfail 780 format(' ## STORM NOT ANNULAR, SCREENING STEP FAILED,', + ' NPASS=',i1,' NFAIL=',i1,15x, + ' ##') iahi = ifix(ahi+0.49) write(luout,782) iahi else write(luout,723) 723 format(25x,'STORM NOT ANNULAR, FAILED SCREENING',/) c write(luout,722) '******************************', + '***********************' write(luout,721) ahi write(luout,722) '******************************', + '***********************' endif return else if (ishort .eq. 1) then write(luout,781) 781 format(' ## PASSED SCREENING STEP, MIGHT BE ANNULAR,', + ' CALCULATE AHI FROM DISCRIMINANT ANALYSIS ##') else write(luout,724) 724 format(25x,'STORM MAY BE ANNULAR, PASSED SCREENING',/, + 23x,'CALCULATE AHI FROM DISCRIMINANT ANALYSIS',/) endif endif 701 format(25x,a31,/) 782 format(' ## AHI=',i3,' (AHI OF 100 IS BEST FIT TO ANN.', + ' STRUC., 1 IS MARGINAL, 0 IS NOT ANNULAR) ##') 721 format(15x,'* ANNULAR HURRICANE INDEX (AHI) VALUE = ',f5.0, + ' *',/,15x, + '* (AHI=100. IS BEST MATCH TO ANNULAR STRUCTURE) *', + /,15x,'* (AHI= 1. IS WORST MATCH TO ANNULAR STRUCTURE) *', + /,15x,'* (AHI= 0. FOR NO ANNULAR STRUCTURE) *') 722 format(15x,a30,a23) 708 format(5x,a33,f5.1,a13,8x,a11) 709 format(5x,a31,f5.1,a10,13x,a11,/) c-----7---------------------------------------------------------------72 c Standardize data gen_sst = ahi_sst(0) u200 = real(iu200(0)) / 10.0 weye_s = (eye_diff - means(1)) / sdev(1) var_s = (var_prof - means(2)) / sdev(2) std_s = (std_cpix - means(3)) / sdev(3) sst_s = (gen_sst - means(4)) / sdev(4) u200_s = (u200 - means(5)) / sdev(5) c Get annular hurricane index call ahindex(weye_s,var_s,std_s,sst_s,u200_s ,dv,dfval,ann_prob) c Calculate annular hurricane index (ahi) from the discriminant value c c Specific df scaling factors c ahi = ahmin at dfmin c ahi = ahmax at dfmax c c dfmin, dfmax based upon 1995-2006 developmental data and should c result in a ~ 96% hit rate and ~4% false alarm rate - JAK c dfmin = -0.3 dfmax = 2.3 ahmin = 1.0 ahmax = 100.0 c ahslope = (ahmax-ahmin)/(dfmax-dfmin) ahyint = ahmin - ahslope*dfmin c ahi = dfval*ahslope + ahyint c if (ahi .lt. 1.0) ahi = 1.0 if (ahi .gt. 100.0) ahi = 100.0 sample_count=sample_count+1 c-----7---------------------------------------------------------------72 c Write data if (ishort .eq. 1) then iahi = ifix(ahi+0.49) write(luout,782) iahi else write(luout,722) '******************************', . '***********************' write(luout,721) ahi write(luout,722) '******************************', . '***********************' endif c c iwcon = 0 c if (iwcon .eq. 1) then c write individual contributions to annular index c write(luout,603) 'CONTRIBUTIONS TO ANNULAR INDEX' c write(luout,604) 'Vertical Shear',' ',dweights(5)*shrd_s + c + dweights(6)*shrg_s c write(luout,605) 'Radius of Coldest Pixel',' ', c + dweights(1)*cpix_s c write(luout,606) 'GOES Core Symmetry Factor',' ', c + dweights(3)*var_s + dweights(4)*std_s c write(luout,607) 'GOES Eye Temperature',' ',dweights(2)*weye_s c write(luout,608) '200 hPa Eddy Fluxes',' ',dweights(8)*refc_s c write(luout,609) '200 hPa Zonal Wind',' ',dweights(7)*u200_s c write(luout,610) 'Storm Intensity',' ',dweights(9)*vmax_s c write(luout,621) '_','_____________________________', c + '__________' c write(luout,611) 'TOTAL',' ', dv c write(luout,622) 'TOTAL > ',div, ' ---->', c + ' ANNULAR STRUCTURE POSSIBLE' c write(luout,623) 'TOTAL < ',div, ' ---->', c + ' ANNULAR STRUCTURE VERY UNLIKELY' c endif 602 format(a15,5x,a36,f4.1,a1,4x,a5) 603 format(/,a56/) 604 format(23x,a14,a16,f7.3) 605 format(23x,a23,a7,f7.3) 606 format(23x,a25,a5,f7.3) 607 format(23x,a20,a10,f7.3) 608 format(23x,a19,a11,f7.3) 609 format(23x,a18,a12,f7.3) 610 format(23x,a15,a15,f7.3) 611 format(23x,a5,a25,f7.3,/) 620 format(a15,a30,a25) 621 format(a24,a29,a7) 622 format(18x,a8,f3.1,a6,a27) 623 format(18x,a8,f3.1,a6,a33) ! If only 1 of the IR files is within 12h of SHIPS data, ! display a note in the data output file, proceed. c if ((irtg.eq.1).or.(irerr.gt.0)) then c write(luout,639) errmsg5 c else c write(luout,639) errmsg0 c endif return 901 write(luout,637) errmsg1 RETURN END c-----7---------------------------------------------------------------72 c-------------------------- SUBROUTINES ------------------------------ c-----7---------------------------------------------------------------72 SUBROUTINE ir_prof_avg2(fn_ird1,fn_ird2,fn_iri1,fn_iri2, + iyr,useir1,useir2,prof_avg,std_avg, + raz,ibuff,irerr) c-----7---------------------------------------------------------------72 c Routine to read in 2 IR radial profile data and average c c c INPUT c fn_ird1 = filename of 1st IR data file c fn_ird2 = filename of 2nd IR data file c fn_iri1 = filename of 1st IR information file c fn_iri2 = filename of 2nd IR information file c iyr = 4-digit storm year c useir1 = integer indicating validity of IRRP1.dat, 0=n, 1=y c useir2 = integer indicating validity of IRRP2.dat, 0=n, 1=y c c OUTPUT c prof_avg = time average of IR profile c std_avg = time average of IR standard deviations c raz = radii (km) of prof_avg and std_avg c ibuff = (integer) If equal to zero, then disregard prof_avg c and std_avg in main program. c c-----7---------------------------------------------------------------72 parameter(maxbyt=1000000) ! max file size (bytes; multiple of 4) byte tot(maxbyt) ! total data file (bytes) parameter(maxele=3000,maxlin=3000) ! max image size (elems,lines) dimension ximage(maxele,maxlin) parameter(maxavg=1000) ! max size of 1D radial profile arrays parameter(radmax=600.) ! max radius of profile output files (km) parameter(maxrad=radmax/4) ! max number of elements in profiles dimension azav(maxrad),raz(maxrad),std(maxrad) ! averaging arrays dimension specr(maxrad),speci(maxrad) ! spectral coefficient arrays parameter(maxtim=1000) ! max number of data files dimension timarray(maxtim) parameter(maxwrd=maxbyt/4) ! max file size (words) integer navi(maxwrd) ! navigation block (words) integer area(64) ! area block (words) equivalence (tot(1),navi(1)) ! fills navigation from total character*80 fn ! area file name character*80 fnout ! generic output file name character*80 pthar ! path to area file logical swap ! little or big endian query logical fnxst ! file name query integer LL(2) ! (lat,lon) <---> (y,x) flag character*12 stnm ! storm name character*9 stnmabr ! abbreviated storm name character*2 bas ! ocean basin (AT,EP,WP,SP,CP,NI,SI) character*11 lmstarr(maxtim) ! LMST in "MM/DD/hh/mm" format parameter(pi=3.1415926535897932384626433832795) ! define pi integer tdiffmin,tdiff,irerr,irerr1,irerr2 character*29 fnrad ! Radial Tb profile data file integer lurad logical radexist real xmsng integer ir1ex,ir2ex,irex integer ir1tg,ir2tg,irtg integer useir1,useir2 character*34 fn_ird1 character*34 fn_ird2 character*34 fn_iri1 character*34 fn_iri2 character*80 pthbt ! path to best track file parameter(maxfix=200) ! max no of best track fixes (per storm) dimension vnz(maxfix),pnz(maxfix) dimension xlanz(maxfix),xlonz(maxfix) dimension tnz(maxfix),sdla(maxfix),sdlo(maxfix) integer im(maxfix/4),id(maxfix/4) c Start and end time of IR time averaging period real bt_start,bt_end c percent pixels along circles dimension pp00(maxrad),pp10(maxrad),pp20(maxrad),pp30(maxrad) dimension pp40(maxrad),pp50(maxrad),pp60(maxrad),pp70(maxrad) parameter(maxbuff=40) real buff_azav(maxrad,maxbuff),buff_std(maxrad,maxbuff), + prof_avg(maxrad),std_avg(maxrad) integer ibuff,ip,ib integer iphold,irhold,iphold_min c-----7---------------------------------------------------------------72 xmsng=-1.0 itim=0 ibuff=0 iphold_min=1000 irnum=0 lurad=46 c Zero out buffer and averaged IR arrays do i=1,maxrad do j=1,maxbuff buff_azav(i,j)=0.0 buff_std(i,j)=0.0 enddo prof_avg(i)=0.0 std_avg(i)=0.0 enddo c-----7---------------------------------------------------------------72 c Read in 1st radial profile c-----7---------------------------------------------------------------72 if (useir1.ne.0) then fnrad=fn_ird1 irnum=irnum+1 open(unit=lurad,file=fnrad,status='old',err=446) call read_radprof(lurad,raz,azav,std,pp50,irerr1) close(lurad) c-----7---------------------------------------------------------------72 c Find radius of coldest Tb pixel and grab standard deviation c at that radius c tbmin=1.e3 irhold=0 iphold=0 do iprof=1,maxrad if ((azav(iprof).ne.xmsng).and.(std(iprof).ne.xmsng)) then iphold=iprof endif enddo do iprof=1,maxrad if ((azav(iprof).lt.tbmin).and.(azav(iprof).ne.xmsng)) then tbmin=azav(iprof) cpix=raz(iprof) std_cpix=std(iprof) irhold=iprof endif enddo ! Check data -- skip if missing data if ((tbmin.eq.xmsng).or.(std_cpix.eq.xmsng)) then tbmin=1.e3 else if ((irhold.ne.0).and.(iphold.ne.0)) then if (iphold.lt.iphold_min) iphold_min=iphold c-----7---------------------------------------------------------------72 c Store current IR data in buffer arrays for averaging c do ip=1,maxrad buff_azav(ip,irnum)=azav(ip) buff_std(ip,irnum)=std(ip) enddo endif endif c-----7---------------------------------------------------------------72 446 continue c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 c Read in 2nd radial profile c-----7---------------------------------------------------------------72 if (useir2.ne.0) then fnrad=fn_ird2 irnum=irnum+1 open(unit=lurad,file=fnrad,status='old',err=449) call read_radprof(lurad,raz,azav,std,pp50,irerr2) close(lurad) c-----7---------------------------------------------------------------72 c Find radius of coldest Tb pixel and grab standard deviation c at that radius c tbmin=1.e3 irhold=0 iphold=0 do iprof=1,maxrad if ((azav(iprof).ne.xmsng).and.(std(iprof).ne.xmsng)) then iphold=iprof endif enddo do iprof=1,maxrad if ((azav(iprof).lt.tbmin).and.(azav(iprof).ne.xmsng)) then tbmin=azav(iprof) cpix=raz(iprof) std_cpix=std(iprof) irhold=iprof endif enddo ! Check data -- skip if missing data if ((tbmin.eq.xmsng).or.(std_cpix.eq.xmsng)) then tbmin=1.e3 else if ((irhold.ne.0).and.(iphold.ne.0)) then if (iphold.lt.iphold_min) iphold_min=iphold c-----7---------------------------------------------------------------72 c Store current IR data in buffer arrays for averaging c do ip=1,maxrad buff_azav(ip,irnum)=azav(ip) buff_std(ip,irnum)=std(ip) enddo endif endif c-----7---------------------------------------------------------------72 449 continue c-----7---------------------------------------------------------------72 if (irnum.ne.0) then ! Average IR data do ip=1,iphold_min prof_avg(ip)=sum(buff_azav(ip,1:irnum))/2 std_avg(ip)=sum(buff_std(ip,1:irnum))/2 enddo ! Fill out rest with missing value, if necessary if (iphold_min.lt.maxrad) then do ip=iphold_min+1,maxrad prof_avg(ip)=xmsng std_avg(ip)=xmsng enddo endif ! Zero out buffer arrays do ip=1,maxrad do ib=1,maxbuff buff_azav(ip,ib)=0.0 buff_std(ip,ib)=0.0 enddo enddo endif irerr = irerr1 + irerr2 ccccc output prof_avg and raz to file RETURN END c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 subroutine read_ships(luls,sname4,ilyr,ilmon,ilday,iltime,ivmx, + iu200,it200, + irefc,ishrd,ishtd,ishrs, + ishts,ishrg,endoffile) c Thomas Cram, CIRA, November 2005 c c Reads information from the SHIPS model reanalysis data files c (lsdiaga_1982_2004_rean.dat, lsdiage_1982_2004_rean.dat) c c INPUT c luls = SHIPS data file unit number c c OUTPUT c sname4 = First 4 letters of storm name c ilyr = 2-digit year c ilmon = UTC month c ilday = UTC day c iltime = UTC hour c ivmx = Maximum winds (kt) c iu200 = 200 mb zonal wind (kt) c it200 = 200 mb temperature (deg C) c irefc = Relative eddy momentum flux convergence (m/s/day) c ishrd = 850-200 mb shear magnitude (kt) c ishtd = Heading (deg) of SHRD shear vector c ishrs = 850-500 mb shear magnitude (kt) c ishts = Heading (deg) of SHRS shear vector c ishrg = Generalized 850-200 mb shear magnitude (kt; takes into c account all levels) c endoffile = Integer specifying if the end of the file has been c reached (0 = no, 1 = yes) c c-----7---------------------------------------------------------------72 c parameter (mft=28) character*180 iline character*110 iheader integer ilyr,ilmon,ilday,iltime,ivmx integer iper,itime(0:mft),iincv(0:mft),ilat(0:mft), + ilon(0:mft),id20c(0:mft), + id26c(0:mft),ihcon(0:mft) integer idist(0:mft),iu200(0:mft),it200(0:mft), + ie000(0:mft),iepos(0:mft),ieneg(0:mft),iepss(0:mft), + ienss(0:mft),irhlo(0:mft),irhmd(0:mft),irhhi(0:mft), + ishrd(0:mft),ishtd(0:mft),ishrs(0:mft),ishts(0:mft), + ishrg(0:mft),ipslv(0:mft),iz850(0:mft),id200(0:mft), + irefc(0:mft),it000(0:mft),ir000(0:mft),iz000(0:mft), + igoes(0:mft),igoesm3(0:mft),ird20(0:mft),ird26(0:mft), + irhcn(0:mft) integer endoffile character*4 sname4 endoffile=0 c Read the SHIPS data file read(luls,110,end=1201,err=1201) sname4,ilyr,ilmon,ilday, + iltime,ivmx,iheader 110 format(1x,a4,1x,3(i2.2),1x,i2.2,1x,i4,a110) 1100 continue c Format read definitions 111 format(a180) 112 format(1x,31(i4,1x)) 114 format(11x,i4) 116 format(11x,29(i4,1x)) 117 format(11x,29(i4,1x),5x,i4) c-----7---------------------------------------------------------------72 c Will read every line until 'LAST' is found or end of file do read(unit=luls,fmt=111,end=1200,err=1200) iline select case (iline(157:160)) ! TIME case('TIME') cc read(iline,112) (itime(k),k=-2,mft) read(iline,116) (itime(k),k=0,mft) ! DELV case('DELV') read(iline,114) iper ! INCV case('INCV') cc read(iline,112) (iincv(k),k=-2,mft) read(iline,116) (iincv(k),k=0,mft) ! LAT case('LAT ') cc read(iline,112) (ilat(k),k=-2,mft) read(iline,116) (ilat(k),k=0,mft) ! LON case('LON ') cc read(iline,112) (ilon(k),k=-2,mft) read(iline,116) (ilon(k),k=0,mft) ! DTL case('DTL') read(iline,116) (idist(k),k= 0,mft) ! D20C case('D20C') cc read(iline,112) (id20c(k),k=-2,mft) read(iline,116) (id20c(k),k=0,mft) ! D26C case('D26C') cc read(iline,112) (id26c(k),k=-2,mft) read(iline,116) (id26c(k),k=0,mft) ! HCON case('HCON') cc read(iline,112) (ihcon(k),k=-2,mft) read(iline,116) (ihcon(k),k=0,mft) ! U200 case('U200') read(iline,116) (iu200(k),k= 0,mft) ! T200 case('T200') read(iline,116) (it200(k),k= 0,mft) ! E000 case('E000') read(iline,116) (ie000(k),k= 0,mft) ! EPOS case('EPOS') read(iline,116) (iepos(k),k= 0,mft) ! ENEG case('ENEG') read(iline,116) (ieneg(k),k= 0,mft) ! EPSS case('EPSS') read(iline,116) (iepss(k),k= 0,mft) ! ENSS case('ENSS') read(iline,116) (ienss(k),k= 0,mft) ! RHLO case('RHLO') read(iline,116) (irhlo(k),k= 0,mft) ! RHMD case('RHMD') read(iline,116) (irhmd(k),k= 0,mft) ! RHHI case('RHHI') read(iline,116) (irhhi(k),k= 0,mft) ! SHRD case('SHRD') read(iline,116) (ishrd(k),k= 0,mft) ! SHTD case('SHTD') read(iline,116) (ishtd(k),k= 0,mft) c Convert ishtd from heading to direction do k=0,mft if (ishtd(k) .lt. imiss) then ishtd(k) = 180 + ishtd(k) if (ishtd(k) .gt. 360) ishtd(k) = ishtd(k)-360 endif enddo ! SHRS case('SHRS') read(iline,116) (ishrs(k),k= 0,mft) ! SHTS case('SHTS') read(iline,116) (ishts(k),k= 0,mft) c Convert ishts from heading to direction do k=0,mft if (ishts(k) .lt. imiss) then ishts(k) = 180 + ishts(k) if (ishts(k) .gt. 360) ishts(k) = ishts(k)-360 endif enddo ! SHRG case('SHRG') read(iline,116) (ishrg(k),k= 0,mft) ! PSLV case('PSLV') read(iline,116) (ipslv(k),k= 0,mft) ! Z850 case('Z850') read(iline,116) (iz850(k),k= 0,mft) ! D200 case('D200') read(iline,116) (id200(k),k= 0,mft) ! REFC case('REFC') read(iline,116) (irefc(k),k= 0,mft) ! T000 case('T000') read(iline,116) (it000(k),k= 0,mft) ! R000 case('R000') read(iline,116) (ir000(k),k= 0,mft) ! Z000 case('Z000') read(iline,116) (iz000(k),k= 0,mft) ! IR00 case('IR00') read(iline,116) (igoes(k),k= 0,mft) ! IRM3 case('IRM3') read(iline,116) (igoesm3(k),k= 0,mft) ! RD20 case('RD20') read(iline,116) (ird20(k),k= 0,mft) ! RD26 case('RD26') read(iline,116) (ird26(k),k= 0,mft) ! NOHC case('NOHC') read(iline,117) (irhcn(k),k= 0,mft),iohclag ! LAST case('LAST') exit !other lines case default continue end select cycle c-----7---------------------------------------------------------------72 1200 continue exit c-----7---------------------------------------------------------------72 enddo 1201 continue endoffile=1 RETURN END c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 c subroutine read_radprof(lurad,raz,azav,std,pp50,irerrflg) c Thomas Cram, May 2005 c c Reads information from the IR brightness temperature radial c profile data. c c INPUT c lurad = unit number for radial profile data file c c OUTPUT c raz = radii (km) c azav = Tb profile c std = standard deviation c pp50 = percentage of -50C pixels c irerrflg = 1.0 if error reading ir radial profile file c c-----7---------------------------------------------------------------72 parameter(maxrad=150) real raz(maxrad),azav(maxrad),std(maxrad), + pp00(maxrad),pp10(maxrad),pp20(maxrad),pp30(maxrad), + pp40(maxrad),pp50(maxrad),pp60(maxrad),pp70(maxrad) integer irerrflg irerrflg=0.0 radtot = 0.0 do iprof=1,maxrad read(unit=lurad,fmt=100,end=567,err=567) + raz(iprof),azav(iprof),std(iprof), + pp00(iprof),pp10(iprof),pp20(iprof), + pp30(iprof),pp40(iprof),pp50(iprof), + pp60(iprof),pp70(iprof) radtot = radtot + 1 enddo 100 format(f6.1,1x,10(f6.2,1x)) 567 continue if (radtot.lt.maxrad) then irerrflg = 1.0 endif return end c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 SUBROUTINE moment(data1,n,ave,adev,sdev,var,skew,curt) c Given an array of DATA1 of length N, this routine returns its mean AVE, c average deviation ADEV, standard deviation SDEV, variance VAR, c skewness SKEW, and kurtosis CURT INTEGER n REAL adev,ave,curt,sdev,skew,var,data1(n) INTEGER j REAL p,s,ep c if(n.le.1)pause 'n must be at least 2 in moment' if (n.le.1) then print*, 'n must be at least 2 in moment' stop endif c First pass to get the mean s=0. do j=1,n s=s+data1(j) enddo ave=s/n c Second pass to get the first (absolute), second, third, and fourth c moments of the deviation from the mean adev=0. var=0. skew=0. curt=0. ep=0. do j=1,n s=data1(j)-ave ep=ep+s adev=adev+abs(s) p=s*s var=var+p p=p*s skew=skew+p p=p*s curt=curt+p enddo adev=adev/n var=(var-ep**2/n)/(n-1) sdev=sqrt(var) if(var.ne.0.)then skew=skew/(n*sdev**3) curt=curt/(n*var**2)-3. else c pause 'no skew or kurtosis when zero variance in moment' write(6,*) 'no skew,kurtosis when zero variance in subr moment' endif return END c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 BLOCK DATA c*********************************************************************** c Contains standard deviations, means, discriminant parameter c weights, and discriminant function dividing value for use in the c annular hurricane linear discriminant analysis. c c Order of array elements: c weye, var, std, sst, u200 c c Last Modified: Feb 16, 2007: JAK c c 1) Reduced number of factors to 5 from 9 c 2) replaced the means and standard deviations to represent the screened c sample in the 1995-2006 developmental data c************************************************************************ REAL sdev(5),means(5),dweights(5),div common /MOMENTS/ sdev,means common /DWEIGHTS/ dweights common /DIVIDER/ div data means/ 56.73, 558.21, 4.23, + 27.68, -8.09 / data sdev/ 21.61, 218.52, 2.45, + 1.04, 5.62 / data dweights/ 0.80944, 0.61429, -0.44537, + -0.80173, -0.14644/ data div/0.75904/ END c-----7---------------------------------------------------------------72 SUBROUTINE ahindex(weye,var,std,gen_sst,u200,dv,val,prob) c-----7---------------------------------------------------------------72 c Subroutine to apply disciminant weights contained in the BLOCK c DATA routine to create discrimnant fucntion value (val) and c a probability associated with val. c c Last Modified: Feburary 16, 2007 - JAK c 1) now uses 5 predictors c 2) new fit to the probability estimation c*********************************************************************** REAL weye,var,std,gen_sst,u200 REAL dv,val,prob ! Discriminant weights (block data) common /DWEIGHTS/ dweights(5) ! Discriminant function divider (block data) common /DIVIDER/ div c-----7---------------------------------------------------------------72 dv=0.0 val=0.0 dv=dweights(1)*weye + dweights(2)*var + + dweights(3)*std + dweights(4)*gen_sst + dweights(5)*u200 val=dv-div ! Determine annular hurricane probability ! ! quadratic function fits the observe PDF from the 1995-2006 ! dependent data if (val.lt.-0.3)then prob=0.0 else if (val .ge. -0.3 .and. val .lt. 1.929)then prob=-0.0183 * val**3 + 0.0689 * val**2 1 +0.2483 * val + 0.1347 else if (val .ge. 1.929) then prob=1.0 endif if (prob.gt.1.0) prob=1.0 RETURN END c c-----7---------------------------------------------------------------72 c-----7---------------------------------------------------------------72 c subroutine chartointmon(charmon,intmon) integer intmon character*3 charmon select case (charmon) case ('JAN') intmon=1 case ('FEB') intmon=2 case ('MAR') intmon=3 case ('APR') intmon=4 case ('MAY') intmon=5 case ('JUN') intmon=6 case ('JUL') intmon=7 case ('AUG') intmon=8 case ('SEP') intmon=9 case ('OCT') intmon=10 case ('NOV') intmon=11 case ('DEC') intmon=12 end select END c ++++END ANNULAR HURRICANE INDEX MODULE++++