/* include file containing all AODT library global variables */ #include "../inc/odtlib.h" /* include file containing all AODT library variable definitions */ #include "../inc/odtlibdefs-x.h" /* include file containing format statements for shared functions */ #include "../inc/odtlibfuncs.h" #define maxsec 24 #define maxsecA 2000 int aodtv64_calcscene(void); void aodtv64_classify(void); void aodtv64_eyeshearcalc( float,float,float,int,float *,float * ); void aodtv64_xxsort( float *, float *, float *, int ); void aodtv64_fminx( float *, int, int *, float * ); void aodtv64_fmaxx( float *, int, int *, float * ); int aodtv64_rmw(float *,float *); /*=====================================================================*/ int aodtv64_calcscene(void) /* Perform Fast Fourier Transform (FFT) analysis and determine scene type via empirically defined threshold values. Inputs : global structure odtcurrent_v64 containing current intensity values Outputs : various elements within structure odtcurrent_v64 Return : -41 : error with FFT routine -51 : cloud temperature value <-100C or >+40C 0 : o.k. ** * * Log: * * T. Piper/SAIC 05/06 Properly allocate two-dimensional array * * T. Piper/SAIC 05/06 Properly free sector * ************************************************************************/ { int nbin=64,iok; int ixx,iyy,izz,iscene,idxcnt,maxsecd2,sxscnt; int *sectorcnt,cnteye; float bd[534],cbd[534],tbd[534]; float radb,rade,radeye,teye,dx2,eyecnt,rngcnt; float xangle,xdist,xtemp,slice; float *sectordiffa,*sectormin; float **sector,*eyearr,*sxs,sectang1,sectang2; float *avex,*stdvx,*skewx,*xs,*i2; float Aaveext,Astdvext,Askewext,Aavesym,Astdvsym,Askewsym; float Eaveeye,Estdveye,Eskeweye; float alsdist,alsradb,alsrade,alssum,alst,alscnt; struct ringdata *tcirc; size_t sofflt; /* initialize temperature histogram bin values */ for(iyy=0;iyydist>=radb)&&(tcirc->dist<=rade)) { teye=(tcirc->temp - 273.16); for(ixx=0;ixx<(nbin-1);ixx++) { if((teye<=bd[ixx])&&(teye>=bd[ixx+1])) { cbd[ixx]=cbd[ixx]+1.0; tbd[ixx]=tbd[ixx]+teye; } } } tcirc=tcirc->nextrec; } /* perform FFT analysis */ iok=aodtv64_fft(cbd,&dx2,&idxcnt); if(iok<0) return -41; /* assign variables based upon region being analyzed */ if(iscene==0) { rngcnt=idxcnt; /* CLOUD TOP */ } else { eyecnt=idxcnt; /* EYE REGION */ } } /* compute various cloud and eye region parameters for classification scheme */ /* allocate memory for arrays */ sectorcnt=(int *)calloc((size_t)maxsec,sizeof(int)); sofflt=sizeof(float); sectormin=(float *)calloc((size_t)maxsec,sofflt); sector=(float **)calloc((size_t)maxsec,sizeof(float*)); for(ixx=0;ixxangle; xdist=tcirc->dist; xtemp=tcirc->temp-273.16; if(xangle==360.0) xangle=0.0; ixx=0; if((xdist>=radb)&&(xdist<=rade)) { while(ixx=sectang1)&&(xangle=0)&&(xdist<=radeye)) { eyearr[cnteye]=xtemp; cnteye++; } /* the following will count all values w/in the different BD curve ranges for the whole cloud region so we can examine the structure of the cloud region later */ tcirc=tcirc->nextrec; } /* position annulus at CW max temp distance and determine mean temp w/in +/- 40km from this distance. If dist is less than 68km from center, annulus will start at 28km */ alscnt=0; alssum=0.0; alsdist=(float)odtcurrent_v64->IR.cwring; alsradb=A_MAX(28.0,alsdist-40.0); alsrade=A_MAX(108.0,alsdist+40.0); tcirc=tcircfirst_v64; while(tcirc!=NULL) { xdist=tcirc->dist; xtemp=tcirc->temp-273.16; if((xdist>=alsradb)&&(xdist<=alsrade)) { alssum=alssum+xtemp; alscnt++; } tcirc=tcirc->nextrec; } alst=alssum/(float)alscnt; odtcurrent_v64->IR.cloudt=alst; if((odtcurrent_v64->IR.cloudt<-100.0)||(odtcurrent_v64->IR.cloudt>40.0)) return -51; /* determine "minimum" temperature for each sector. This is not the actual lowest temperature, but instead is the temperature value of the coldest 90% of the values within the sector. This will, hopefully, eliminate some outliers */ /* allocate memory */ xs=(float *)calloc((size_t)maxsecA,sofflt); i2=(float *)calloc((size_t)maxsecA,sofflt); sxs=(float *)calloc((size_t)maxsecA,sofflt); for(ixx=0;ixxIR.cloudt2=Aaveext; /* these are used to examine symmetry of convection */ maxsecd2=maxsec/2; for (ixx=0;ixxIR.eyestdv=Estdveye; odtcurrent_v64->IR.cloudsymave=Aavesym; odtcurrent_v64->IR.eyefft=(int)eyecnt; odtcurrent_v64->IR.cloudfft=(int)rngcnt; /* free memory */ free(sectordiffa); free(skewx); free(stdvx); free(avex); for(ixx=0;ixxIR.eyet; eyefft=odtcurrent_v64->IR.eyefft; eyestdv=odtcurrent_v64->IR.eyestdv; cloudtemp=odtcurrent_v64->IR.cloudt; cloudcwt=odtcurrent_v64->IR.cwcloudt; cloudfft=odtcurrent_v64->IR.cloudfft; cloudsyma=odtcurrent_v64->IR.cloudsymave; xlat=odtcurrent_v64->IR.latitude; xlon=odtcurrent_v64->IR.longitude; /* compute cloud category */ for(ixx=0;ixx<9;ixx++) { if((cloudtemp<=ebd_v64[ixx])&&(cloudtemp>ebd_v64[ixx+1])) { cloudcat=ixx; } } /* compute eye category */ for(ixx=0;ixx<9;ixx++) { if((eyetemp<=ebd_v64[ixx])&&(eyetemp>ebd_v64[ixx+1])) { eyecat=ixx; } } /* compute ave eye category */ for(ixx=0;ixx<9;ixx++) { if((cloudcwt<=ebd_v64[ixx])&&(cloudcwt>ebd_v64[ixx+1])) { cwtcat=ixx; } } diffcat=A_MAX(0,A_MIN(cloudcat,cwtcat)-eyecat); diffcloudcat=cloudcat-cwtcat; curtime=aodtv64_calctime(odtcurrent_v64->IR.date,odtcurrent_v64->IR.time); curtimem12=curtime-0.5; /* determine last Final T# value for curved band/other scene check */ eyefound=FALSE; if((odthistoryfirst_v64==0)||(hfile_v64==(char *)NULL)) { lasttno12=A_MIN(8.0,A_MAX(1.0,osstr_v64)); } else { odthistory=odthistoryfirst_v64; cbfound=FALSE; while(odthistory!=0) { xtime=aodtv64_calctime(odthistory->IR.date,odthistory->IR.time); landcheck=TRUE; if(((oland_v64)&&(odthistory->IR.land==1))||(odthistory->IR.Traw<1.0)) landcheck=FALSE; if((xtime=curtimem12)&&(!cbfound)) { lasttno12=odthistory->IR.Tfinal; cbfound=TRUE; } lasttno=odthistory->IR.Tfinal; if(odthistory->IR.eyescene<=2) eyefound=TRUE; } odthistory=odthistory->nextrec; } /* check for large break in history file */ if(!cbfound) lasttno12=lasttno; } /* CLASSIFY EYE REGION */ if(eyefft<=2) { sceneeye=6; /* NO EYE */ if(eyecat==0) { sceneeye=0; /* CLEAR EYE */ } if((diffcat>=2)&&(eyecat>0)) sceneeye=5; } if((eyefft>=3)&&(eyefft<=6)) { if(eyecat==0) { sceneeye=0; /* CLEAR EYE */ } else if(eyecat==1) { sceneeye=4; /* RAGGED EYE */ if(eyestdv>=25.0) { sceneeye=0; /* CLEAR EYE */ } } else { sceneeye=6; /* NO EYE */ if((diffcat>=2)&&(eyecat>0)) sceneeye=5; } } if((eyefft>=7)&&(eyefft<=9)) { if(eyecat==0) { sceneeye=0; /* CLEAR EYE */ } else if(eyecat==1) { sceneeye=4; /* RAGGED EYE */ if(eyestdv>=20.0) { sceneeye=0; /* CLEAR EYE */ } } else { sceneeye=5; /* OBSCURED EYE */ } } if(eyefft>=10) { if(eyecat==0) { sceneeye=0; /* CLEAR EYE */ } else if(eyecat==1) { sceneeye=4; /* RAGGED EYE */ } else { sceneeye=5; /* OBSCURED EYE */ } } if(eyecat<=1) { if(sceneeye==6) { sceneeye=2; /* LARGE EYE */ if(cwtcat<4) { sceneeye=3; /* LARGE RAGGED EYE */ } } } eyesize=0.0; if(sceneeye<=4) { /* obtain eye size and shape parameters / tempval=ebd_v64[2]+273.16; aodtv64_eyeshearcalc(xlat,xlon,tempval,2,&essizeDG,&esdiffDG); eyesize=essizeDG; */ /* compute radius of maximum wind and eye size */ aodtv64_rmw(&rmw,&eyesize); odtcurrent_v64->IR.rmw=rmw; odtcurrent_v64->IR.eyesize=eyesize; } /* adjustments to FFT determined scenes */ if(sceneeye==0) { if(eyesize>35.0) { sceneeye=2; /* large eye */ } } if(sceneeye==4) { if(eyesize>35.0) sceneeye=3; /* large ragged eye */ } if((sceneeye==2)||(sceneeye==3)) { if(eyesize<35.0) { sceneeye=0; /* clear eye */ } } /* CLASSIFY CLOUD REGION */ cbring=0; cbringval=0; cbringvalmax=0; cbringlatmax=xlat; cbringlonmax=xlon; /* check threshold for curved band or other anaysis */ shear=FALSE; cbgray=TRUE; irrcdo=FALSE; cbscene=FALSE; if(cwtcat==0) { /* shear */ shear=TRUE; cbscene=TRUE; irrcdo=FALSE; if(cloudcat>=2) { /* curved band */ shear=FALSE; } } else if(cwtcat==1) { irrcdo=FALSE; cbscene=TRUE; if(cloudcat<=1) { /* shear */ shear=TRUE; } else if(cloudcat==2) { if(cloudsyma>=30) { /* shear */ shear=TRUE; if(eyetemp<=cloudcwt) { /* irregular cdo */ irrcdo=TRUE; shear=FALSE; } } else { /* curved band */ shear=FALSE; } } else { if(cloudsyma>=30) { /* shear */ shear=TRUE; if(eyetemp<=cloudcwt) { /* irregular cdo */ irrcdo=TRUE; shear=FALSE; } } else { shear=FALSE; /* curved band */ if((lasttno12>=3.5)||(eyefound)) { /* eye */ cbscene=FALSE; } } } } else if(cwtcat==2) { irrcdo=FALSE; cbscene=TRUE; if(cloudcat<=2) { if(cloudsyma>=50) { /* shear */ shear=TRUE; if(eyetemp<=cloudcwt) { /* irregular cdo */ irrcdo=TRUE; shear=FALSE; } } else { shear=FALSE; /* curved band */ if((lasttno12>=3.5)||(eyefound)) { /* eye */ cbscene=FALSE; } else { /* curved band */ if(eyecat>=3) { /* irregular cdo */ irrcdo=TRUE; } } } } else { shear=FALSE; irrcdo=FALSE; cbscene=TRUE; /* curved band */ if((lasttno12>=3.5)||(eyefound)) { /* eye */ cbscene=FALSE; } else { if(eyecat>=3) { /* irregular cdo */ irrcdo=TRUE; } } } } else if(cwtcat==3) { shear=FALSE; irrcdo=FALSE; cbscene=TRUE; if((lasttno12>=3.5)||(eyefound)) { /* eye */ cbscene=FALSE; } } else { /* eye scene */ cbscene=FALSE; shear=FALSE; irrcdo=FALSE; } L100: if(cbscene) { if(shear) { scenecloud=4; /* SHEAR */ tempval=ebd_v64[3]+273.16; aodtv64_eyeshearcalc(xlat,xlon,tempval,3,&essizeDG,&esdiffDG); eyesize=A_MAX(4.0,essizeDG); } else if(irrcdo) { scenecloud=2; /* IRREGULAR CDO */ } else { cbfound=FALSE; L200: if(cbgray) { /* perform Curved Band analysis */ ixx=4; /* start with DARK GRAY */ while((ixx>=2)&&(!cbfound)) { tempval=ebd_v64[ixx]+273.16; aodtv64_logspiral(xlat,xlon,tempval,1,&spiral,&lat1,&lon1); if((spiral>=9)||(ixx==2)) { /* 10 = .375% -- 10 ==> 9 arcs of 15 degrees */ if(spiral>25) { if(ixx==4) { cbgray=FALSE; goto L200; } else { ixx=0; } } else { if((ixx==2)&&(spiral<7)) { /* 7 = .25% -- 10 ==> 6 arcs of 15 degrees */ /* probably shear */ cbfound=FALSE; shear=TRUE; goto L100; } else { cbfound=TRUE; } } } else { ixx--; } } } else { /* try BLACK and WHITE rings */ cbscene=FALSE; ixx=cwtcat; if(ixx>6) goto L100; while((ixx<=6)&&(!cbfound)) { if((eyetemp-cloudtemp)<2.0) { ixx=99; } else { tempval=ebd_v64[ixx]+273.16; aodtv64_logspiral(xlat,xlon,tempval,1,&spiral,&lat1,&lon1); if(((spiral<9)||(spiral>25))&&(ixx==6)) { /* probably CDO/EMBC */ ixx=99; } else { if((spiral>=9)&&(spiral<=25)) { cbfound=TRUE; } else { ixx++; } } } } } if(cbfound) { cbring=ixx; cbringval=spiral; scenecloud=3; /* CURVED BAND */ /* search for maximum curved band analysis location within 1-degree box */ tempval=ebd_v64[cbring]+273.16; if(osearch_v64) { aodtv64_logspiral(xlat,xlon,tempval,2,&spiralmax,&lat2,&lon2); cbringvalmax=spiralmax; cbringlatmax=lat2; cbringlonmax=lon2; } } else { scenecloud=0; if(eyecat>0) sceneeye=4; if(eyecat>=cloudcat) sceneeye=6; } } if(scenecloud>=2) sceneeye=6; /* NO EYE */ } else { if(cloudfft==0) { scenecloud=0; /* UNIFORM */ } else if((cloudfft>=1)&&(cloudfft<=7)) { scenecloud=0; /* UNIFORM */ if((diffcloudcat>=1)&&(cloudsyma>=8.0)) { scenecloud=1; /* EMBEDDED CENTER */ } } else { if((diffcloudcat<=0)&&(cloudsyma>=35.0)) { scenecloud=2; /* IRREGULAR CDO */ } else { scenecloud=0; /* UNIFORM */ if((diffcloudcat>=1)&&(cloudsyma>=8.0)) { scenecloud=1; /* EMBEDDED CENTER */ } } } } if((scenecloud==0)&&(sceneeye==6)) { /* CDO...check size */ ixx=A_MIN(4,eyecat); tempval=ebd_v64[ixx]+273.16; aodtv64_eyeshearcalc(xlat,xlon,tempval,1,&cdosize,&cdosizex); eyesize=cdosize; /* not used at the moment, but I'll leave it */ } odtcurrent_v64->IR.eyescene=sceneeye; odtcurrent_v64->IR.cloudscene=scenecloud; odtcurrent_v64->IR.eyesceneold=-1; odtcurrent_v64->IR.cloudsceneold=-1; odtcurrent_v64->IR.eyesize=eyesize; odtcurrent_v64->IR.ringcb=cbring; odtcurrent_v64->IR.ringcbval=cbringval; odtcurrent_v64->IR.ringcbvalmax=cbringvalmax; odtcurrent_v64->IR.ringcblatmax=cbringlatmax; odtcurrent_v64->IR.ringcblonmax=cbringlonmax; } void aodtv64_classifyredo(void) { int ixx,scene,cbring,cbringval,spiral,spiralmax; int cbringvalmax; float xlat,xlon,tempval; float lat1,lon1,lat2,lon2,essizeDG,esdiffDG; float eyesize,cbringlatmax,cbringlonmax; logical cbfound=FALSE; xlat=odtcurrent_v64->IR.latitude; xlon=odtcurrent_v64->IR.longitude; scene=odtcurrent_v64->IR.cloudscene; cbringvalmax=0; cbringlatmax=xlat; cbringlonmax=xlon; if(scene==3) { /* perform curved band analysis -- find length of spiral arc */ ixx=2; while((ixx<=4)&&(!cbfound)) { tempval=ebd_v64[ixx]+273.16; /* determine curved band analysis at user selected center */ aodtv64_logspiral(xlat,xlon,tempval,1,&spiral,&lat1,&lon1); cbring=ixx; cbringval=spiral; /* search for maximum curved band analysis location within 1-degree box */ if(osearch_v64) { aodtv64_logspiral(xlat,xlon,tempval,2,&spiralmax,&lat2,&lon2); cbringvalmax=spiralmax; cbringlatmax=lat2; cbringlonmax=lon2; } if(spiral<=25) { cbfound=TRUE; } ixx++; } if(cbring==4) { cbringval=A_MIN(25,cbringval); cbringvalmax=A_MIN(25,cbringvalmax); cbringlatmax=xlat; cbringlonmax=xlon; } eyesize=0.0; } else { tempval=ebd_v64[3]+273.16; aodtv64_eyeshearcalc(xlat,xlon,tempval,3,&essizeDG,&esdiffDG); eyesize=essizeDG; cbring=0; cbringval=0; } odtcurrent_v64->IR.eyesize=eyesize; odtcurrent_v64->IR.ringcb=cbring; odtcurrent_v64->IR.ringcbval=cbringval; odtcurrent_v64->IR.ringcbvalmax=cbringvalmax; odtcurrent_v64->IR.ringcblatmax=cbringlatmax; odtcurrent_v64->IR.ringcblonmax=cbringlonmax; } void aodtv64_eyeshearcalc( float xlat,float xlon,float tempval,int atype,float *valb,float *valc) /* Determine eye size or shear distance for a given scene. Inputs : xlat - center latitude of analysis grid xlon - center longitude of analysis grid tempval - temperature threshold value to be used atype - analysis type (1-cdo size,2-eye size,3-shear distance) Outputs : valb - eye/cdo radius or shear distance valc - eye/cdo symmetry value or 0 */ { int ixx,iyy,np; float xdist,xangle,smalldist,vc; float *zlat,*zlon; float a1,a2,a3,a4; /* allocate memory */ zlat=(float *)calloc((size_t)bufsiz,sizeof(float)); zlon=(float *)calloc((size_t)bufsiz,sizeof(float)); /* initialize arrays */ np=0; if(atype==1) { a1=0.0;a2=0.0;a3=0.0;a4=0.0; } else { a1=999.9;a2=999.9;a3=999.9;a4=999.9; } for(ixx=0;ixxnumx;ixx++) { for(iyy=0;iyynumy;iyy++) { if(areadata_v64->temp[iyy][ixx]<=tempval) { zlat[np]=areadata_v64->lat[iyy][ixx]; zlon[np]=areadata_v64->lon[iyy][ixx]; np++; } } } /* eye size determination - RETURNS RADIUS */ if(atype<=2) { for(ixx=0;ixxa1)) a1=xdist; if((A_ABS(xangle-135.0)<=15.0)&&(xdist>a2)) a2=xdist; if((A_ABS(xangle-225.0)<=15.0)&&(xdist>a3)) a3=xdist; if((A_ABS(xangle-315.0)<=15.0)&&(xdist>a4)) a4=xdist; } else { /* determine size of EYE */ if((A_ABS(xangle-45.0)<=15.0)&&(xdist*x) { *x=f[i]; *im=i; } } } int aodtv64_rmw(float *rmw,float *eyesize) /* Determine radius of maximum wind based upon Jim Kossin's regression based scheme Inputs : ix0 - element location of center point iy0 - line location of center point Outputs : rmw - radius of maximum wind distance eyesize - eye size radius (km) -1 = error/eyewall not found 0 = radius found */ { int ixmin,ixmax,iymin,iymax; int ixc,iyc,i,ix,iy,idx1,idy1,idx2,idy2; float dx1,dx2,dy1,dy2,dav,xlat,xlon,xclat,xclon,xangle; float tcrit=228.0,warm=223.0;; /* calculate cursorx/cursory from numx/numy... values should be 0.5*numx/y */ ixc=areadata_v64->numx/2; iyc=areadata_v64->numy/2; ixmax=A_MIN(areadata_v64->numx,ixc+320); ixmin=A_MAX(0,ixc-320); iymax=A_MIN(areadata_v64->numy,iyc+240); iymin=A_MAX(0,iyc-240); if(odtcurrent_v64->IR.cloudt>=warm) { tcrit=(odtcurrent_v64->IR.eyet+(2.0*odtcurrent_v64->IR.cloudt))/3.0; } *rmw=-99.9; *eyesize=-99.9; /* iterate five times */ for(i=0;i<5;i++) { ix=ixc; while(areadata_v64->temp[iyc][ix]>tcrit) { ix=ix-1; if(ix==ixmin) { return -1; } } idx1=ix; ix=ixc; while(areadata_v64->temp[iyc][ix]>tcrit) { ix=ix+1; if(ix==ixmax) { return -1; } } idx2=ix; iy=iyc; while(areadata_v64->temp[iy][ixc]>tcrit) { iy=iy-1; if(iy==iymin) { return -1; } } idy1=iy; iy=iyc; while(areadata_v64->temp[iy][ixc]>tcrit) { iy=iy+1; if(iy==iymax) { return -1; } } idy2=iy; ixc=(int)((((float)(idx1+idx2))/2.0)); iyc=(int)((((float)(idy1+idy2))/2.0)); } xclat=areadata_v64->lat[iyc][ixc]; xclon=areadata_v64->lon[iyc][ixc]; xlat=areadata_v64->lat[iyc][idx1]; xlon=areadata_v64->lon[iyc][idx1]; aodtv64_distance(xlat,xlon,xclat,xclon,1,&dx1,&xangle); xlat=areadata_v64->lat[iyc][idx2]; xlon=areadata_v64->lon[iyc][idx2]; aodtv64_distance(xlat,xlon,xclat,xclon,1,&dx2,&xangle); xlat=areadata_v64->lat[idy1][ixc]; xlon=areadata_v64->lon[idy1][ixc]; aodtv64_distance(xlat,xlon,xclat,xclon,1,&dy1,&xangle); xlat=areadata_v64->lat[idy2][ixc]; xlon=areadata_v64->lon[idy2][ixc]; aodtv64_distance(xlat,xlon,xclat,xclon,1,&dy2,&xangle); dav=(dx1+dx2+dy1+dy2)/4.0; if(dav>0.0) { *rmw=2.8068+(0.8361*dav); /* Howard's coeffs */ *eyesize=dav; } return 0; }