001 /* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2013 005 * Space Science and Engineering Center (SSEC) 006 * University of Wisconsin - Madison 007 * 1225 W. Dayton Street, Madison, WI 53706, USA 008 * https://www.ssec.wisc.edu/mcidas 009 * 010 * All Rights Reserved 011 * 012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and 013 * some McIDAS-V source code is based on IDV and VisAD source code. 014 * 015 * McIDAS-V is free software; you can redistribute it and/or modify 016 * it under the terms of the GNU Lesser Public License as published by 017 * the Free Software Foundation; either version 3 of the License, or 018 * (at your option) any later version. 019 * 020 * McIDAS-V is distributed in the hope that it will be useful, 021 * but WITHOUT ANY WARRANTY; without even the implied warranty of 022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 023 * GNU Lesser Public License for more details. 024 * 025 * You should have received a copy of the GNU Lesser Public License 026 * along with this program. If not, see http://www.gnu.org/licenses. 027 */ 028 029 package edu.wisc.ssec.mcidasv.control.cyclone; 030 031 import java.util.ArrayList; 032 import java.util.Iterator; 033 import java.util.List; 034 035 /** 036 * Created by IntelliJ IDEA. User: yuanho Date: Feb 26, 2009 Time: 10:02:45 AM 037 * To change this template use File | Settings | File Templates. 038 */ 039 public class StormAODTSceneType { 040 041 /** _more_ */ 042 static int maxsec = 24; 043 044 /** _more_ */ 045 static int maxsecA = 2000; 046 047 /** _more_ */ 048 static double PI = 3.14159265358979323846; 049 050 /** 051 * _more_ 052 * 053 * @param odtcurrent 054 * _more_ 055 * @param rmwsizeman_v72 056 * _more_ 057 * @param areadata 058 * _more_ 059 * @param osstr_v72 060 * _more_ 061 * @param osearch_v72 062 * _more_ 063 * 064 * @return _more_ 065 */ 066 static float[] aodtv72_calcscene(StormAODTInfo.IRData odtcurrent, 067 int rmwsizeman_v72, StormAODTInfo.DataGrid areadata, 068 float osstr_v72, boolean osearch_v72) 069 /* 070 * Perform Fast Fourier Transform (FFT) analysis and determine scene type 071 * via empirically defined threshold values. Inputs : global structure 072 * odtcurrent_v72 containing current intensity values Outputs : various 073 * elements within structure odtcurrent_v72 Return : -41 : error with FFT 074 * routine -51 : cloud temperature value <-100C or >+40C 0 : o.k. 075 */ 076 { 077 078 int nbin = 64, iok, a, b, bptr; 079 int ixx, iyy, izz, iscene, idxcnt, maxsecd2, sxscnt; 080 int[] sectorcnt; 081 int cnteye; 082 float[] bd, cbd, tbd; 083 084 float radb, rade, radeye, teye, dx2, eyecnt = 0, rngcnt = 0; 085 float xangle, xdist, xtemp, slice; 086 float[] sectordiffa, sectormin; 087 float[][] sector; 088 float[] eyearr, sxs; 089 float sectang1, sectang2; 090 float[] avex, stdvx, skewx, xs, i2; 091 float Aaveext, Astdvext, Askewext, Aavesym, Astdvsym, Askewsym; 092 float Eaveeye, Estdveye, Eskeweye; 093 float alsdist, alsradb, alsrade, alssum, alst, alscnt; 094 StormAODTInfo.RingData tcirc; 095 096 float eyetemp; 097 float eyecdosize, rmw; 098 int eyecat; 099 100 /* initialize temperature histogram bin values */ 101 bd = new float[534]; 102 cbd = new float[534]; 103 tbd = new float[534]; 104 for (iyy = 0; iyy < nbin; iyy++) { 105 bd[iyy] = 26.0f - (float) iyy * 2.0f; 106 } 107 /* 108 * set up arrays for FFT ananlysis. iscene=0 will perform FFT for cloud 109 * top region while iscene=1 will perform FFT for eye region 110 */ 111 int cursorx = areadata.numx / 2; 112 int cursory = areadata.numy / 2; 113 List<StormAODTInfo.RingData> tcircfirst = aodtv72_readcirc(cursorx, 114 cursory, areadata); 115 116 for (iscene = 0; iscene <= 1; iscene++) { 117 for (iyy = 0; iyy < nbin; iyy++) { 118 cbd[iyy] = 0.0f; 119 tbd[iyy] = 0.0f; 120 } 121 122 /* define start and end radii values */ 123 if (iscene == 0) { 124 /* CLOUD TOP */ 125 radb = (float) StormAODTInfo.kstart_v72; 126 rade = (float) StormAODTInfo.kend_v72; 127 } else { 128 /* EYE REGION */ 129 radb = 0.0f; 130 rade = (float) StormAODTInfo.kstart_v72; 131 } 132 133 /* load arrays for FFT analysis */ 134 Iterator iit = tcircfirst.iterator(); 135 136 while (iit.hasNext()) { 137 tcirc = (StormAODTInfo.RingData) iit.next(); 138 if ((tcirc.dist >= radb) && (tcirc.dist <= rade)) { 139 teye = (tcirc.temp - 273.16f); 140 for (ixx = 0; ixx < (nbin - 1); ixx++) { 141 if ((teye <= bd[ixx]) && (teye >= bd[ixx + 1])) { 142 cbd[ixx] = cbd[ixx] + 1.0f; 143 tbd[ixx] = tbd[ixx] + teye; 144 } 145 } 146 } 147 } 148 149 /* perform FFT analysis */ 150 float[] fftOut = aodtv72_fft(cbd); 151 if (fftOut == null) { 152 return null; // return -41; 153 } 154 155 /* assign variables based upon region being analyzed */ 156 if (iscene == 0) { 157 rngcnt = fftOut[1]; /* CLOUD TOP */ 158 } else { 159 eyecnt = fftOut[1]; /* EYE REGION */ 160 } 161 } 162 163 /* 164 * compute various cloud and eye region parameters for classification 165 * scheme 166 */ 167 168 /* allocate memory for arrays */ 169 170 eyearr = new float[maxsecA]; 171 sectorcnt = new int[maxsec]; 172 sectormin = new float[maxsec]; 173 sector = new float[maxsec][maxsecA]; 174 for (ixx = 0; ixx < maxsec; ixx++) { 175 sectorcnt[ixx] = 0; 176 sectormin[ixx] = 999.0f; 177 for (iyy = 0; iyy < maxsecA; iyy++) { 178 sector[ixx][iyy] = -999.99f; 179 } 180 } 181 182 /* load array for analysis */ 183 radb = (float) StormAODTInfo.kstart_v72; 184 rade = (float) StormAODTInfo.kend_v72; 185 radeye = (float) StormAODTInfo.kstart_v72; 186 Iterator it = tcircfirst.iterator(); 187 188 slice = 360.0f / (float) maxsec; 189 cnteye = 0; 190 while (it.hasNext()) { 191 tcirc = (StormAODTInfo.RingData) it.next(); 192 xangle = tcirc.angle; 193 xdist = tcirc.dist; 194 xtemp = tcirc.temp - 273.16f; 195 if (xangle == 360.0) { 196 xangle = 0.0f; 197 } 198 ixx = 0; 199 if ((xdist >= radb) && (xdist <= rade)) { 200 while (ixx < maxsec) { 201 sectang1 = (float) Math.max(0.0, (float) ixx * slice); 202 sectang2 = (float) Math.min(360.0, (float) (ixx + 1) 203 * slice); 204 if ((xangle >= sectang1) && (xangle < sectang2)) { 205 sector[ixx][sectorcnt[ixx]] = xtemp; 206 sectorcnt[ixx]++; 207 ixx = maxsec; 208 } else { 209 ixx++; 210 } 211 } 212 } 213 if ((xdist >= 0) && (xdist <= radeye)) { 214 eyearr[cnteye] = xtemp; 215 cnteye++; 216 } 217 /* 218 * the following will count all values w/in the different BD curve 219 * ranges for the whole cloud region so we can examine the structure 220 * of the cloud region later 221 */ 222 // tcirc=tcirc->nextrec; 223 } 224 225 /* 226 * position annulus at CW max temp distance and determine mean temp w/in 227 * +/- 40km from this distance. If dist is less than 68km from center, 228 * annulus will start at 28km 229 */ 230 alscnt = 0; 231 alssum = 0.0f; 232 alsdist = (float) odtcurrent.cwring; 233 alsradb = Math.max(28.0f, alsdist - 40.0f); 234 alsrade = Math.max(108.0f, alsdist + 40.0f); 235 it = tcircfirst.iterator(); 236 while (it.hasNext()) { 237 tcirc = (StormAODTInfo.RingData) it.next(); 238 xdist = tcirc.dist; 239 xtemp = tcirc.temp - 273.16f; 240 if ((xdist >= alsradb) && (xdist <= alsrade)) { 241 alssum = alssum + xtemp; 242 alscnt++; 243 } 244 // tcirc=tcirc->nextrec; 245 } 246 alst = alssum / (float) alscnt; 247 // odtcurrent.cloudt=alst; 248 if ((odtcurrent.cloudt < -100.0) || (odtcurrent.cloudt > 40.0)) { 249 return null; // return -51; 250 } 251 252 /* 253 * determine "minimum" temperature for each sector. This is not the 254 * actual lowest temperature, but instead is the temperature value of 255 * the coldest 90% of the values within the sector. This will, 256 * hopefully, eliminate some outliers 257 */ 258 259 /* allocate memory */ 260 xs = new float[maxsecA]; 261 i2 = new float[maxsecA]; 262 sxs = new float[maxsecA]; 263 264 for (ixx = 0; ixx < maxsec; ixx++) { 265 sxscnt = sectorcnt[ixx]; 266 for (iyy = 0; iyy < sxscnt; iyy++) { 267 sxs[iyy] = sector[ixx][iyy]; 268 } 269 aodtv72_xxsort(sxs, xs, i2, sxscnt); 270 izz = (int) (sxscnt - (sxscnt * .1f)); 271 sectormin[ixx] = xs[izz]; 272 } 273 274 /* free memory */ 275 276 /* determine averages, standard deviations and skews for each sector */ 277 /* allocate memory */ 278 avex = new float[maxsec]; 279 stdvx = new float[maxsec]; 280 skewx = new float[maxsec]; 281 sectordiffa = new float[maxsec]; 282 283 for (ixx = 0; ixx < maxsec; ixx++) { 284 float[] out = aodtv72_calcskew(sector[ixx], sectorcnt[ixx]); 285 avex[ixx] = out[0]; 286 stdvx[ixx] = out[1]; 287 skewx[ixx] = out[2]; 288 } 289 290 float[] out = aodtv72_calcskew(avex, maxsec); 291 Aaveext = out[0]; 292 Astdvext = out[1]; 293 Askewext = out[2]; 294 // odtcurrent.cloudt2=Aaveext; 295 296 /* these are used to examine symmetry of convection */ 297 maxsecd2 = maxsec / 2; 298 for (ixx = 0; ixx < maxsecd2; ixx++) { 299 sectordiffa[ixx] = Math.abs(avex[ixx] - avex[maxsecd2 + ixx]); 300 } 301 out = aodtv72_calcskew(sectordiffa, maxsecd2); 302 Aavesym = out[0]; 303 Astdvsym = out[1]; 304 Askewsym = out[2]; 305 /* these are used to examine properties of the eye region */ 306 out = aodtv72_calcskew(eyearr, cnteye); 307 Eaveeye = out[0]; 308 Estdveye = out[1]; 309 Eskeweye = out[2]; 310 311 // odtcurrent.eyestdv=Estdveye; 312 // odtcurrent.cloudsymave=Aavesym; 313 // odtcurrent.eyefft=(int)eyecnt; 314 // odtcurrent.cloudfft=(int)rngcnt; 315 316 /* free memory */ 317 318 /* assign scenetype value in structure odtcurrent_v72 */ 319 return aodtv72_classify(odtcurrent, rmwsizeman_v72, areadata, 320 osstr_v72, osearch_v72, alst, Aaveext, Estdveye, Aavesym, 321 eyecnt, rngcnt); 322 323 } 324 325 /** 326 * _more_ 327 * 328 * @param odtcurrent 329 * _more_ 330 * @param rmwsizeman 331 * _more_ 332 * @param areadata_v72 333 * _more_ 334 * @param osstr_v72 335 * _more_ 336 * @param osearch_v72 337 * _more_ 338 * @param alst 339 * _more_ 340 * @param Aaveext 341 * _more_ 342 * @param Estdveye 343 * _more_ 344 * @param Aavesym 345 * _more_ 346 * @param eyecnt 347 * _more_ 348 * @param rngcnt 349 * _more_ 350 * 351 * @return _more_ 352 */ 353 354 static float[] aodtv72_classify(StormAODTInfo.IRData odtcurrent, 355 int rmwsizeman, StormAODTInfo.DataGrid areadata_v72, 356 float osstr_v72, boolean osearch_v72, float alst, float Aaveext, 357 float Estdveye, float Aavesym, float eyecnt, float rngcnt) 358 /* 359 * Classify scene type based on FFT analysis and histogram temperatures 360 * using empirically defined threshold values. Inputs : global structure 361 * odtcurrent_v72 containing current image analysis Outputs : scenetype in 362 * structure odtcurrent_v72 is modified 363 * 364 * SCENE TYPES : EYE REGION CLOUD REGION 0 - clear 0 - uniform 1 - pinhole 1 365 * - embedded center 2 - large 2 - irregular cdo 3 - none 3 - curved band 4 366 * - shear 367 */ 368 { 369 370 int iok, ixx, iyy, cloudfft = 0, cloudcat = 0, eyefft, eyecat = 0, cwtcat = 0, diffcat; 371 int cbring, cbringval, diffcloudcat; 372 int sceneeye, scenecloud, spiral = 0, spiralmax; 373 int lastcscene, lastescene, cbringvalmax; 374 float xlat, xlon, tempval, lasttno, lasttno12; 375 float eyetemp, cloudtemp, cloudcwt, eyestdv, cloudsyma; 376 float essizeDG = 0.0f, esdiffDG = 0.0f; 377 float lat1, lon1, lat2, lon2; 378 float eyecdosize, diffcloudt, rmw; 379 float cbringlatmax, cbringlonmax; 380 double curtime, curtimem12, xtime, lastvalidtime; 381 382 boolean cbfound, cbscene, cbgray, shear, irrcdo, landcheck; 383 float[] cdodiam = { 0.0f, 85.0f, 140.0f, 195.0f, 250.0f, 999.0f }; 384 float xpart, ddvor; 385 int cdocat; 386 387 boolean embdd = false, checkembc = false; 388 float Ea, Eb, Ec, Ed, Ee, eyeval, Ca, Cb, Cc, Cd, Ce, cloudval; 389 float diffeyecloudt, eyecloudcatdiff, eyecwtcatdiff, cloudcatdiff; 390 float eyepart = 0, cloudpart = 0, cwtpart = 0, diffcat2, lastvalidtno, lastr9, maxtno; 391 float[] cdomax = { 0.0f, 0.4f, 0.4f, 0.5f, 0.5f, 0.6f, 0.6f }; 392 int diffeyecloudcat; 393 boolean foundeye, foundm12; 394 395 eyetemp = odtcurrent.eyet; 396 eyefft = (int) eyecnt; 397 eyestdv = Estdveye; 398 cloudtemp = alst; 399 cloudcwt = odtcurrent.cwcloudt; 400 cloudfft = (int) rngcnt; 401 cloudsyma = Aavesym; 402 xlat = odtcurrent.latitude; 403 xlon = odtcurrent.longitude; 404 405 for (ixx = 0; ixx < 10; ixx++) { 406 /* compute cloud category */ 407 if ((cloudtemp <= StormAODTInfo.ebd_v72[ixx]) 408 && (cloudtemp > StormAODTInfo.ebd_v72[ixx + 1])) { 409 cloudcat = ixx; 410 xpart = (float) ((cloudtemp - StormAODTInfo.ebd_v72[cloudcat]) / (StormAODTInfo.ebd_v72[cloudcat + 1] - StormAODTInfo.ebd_v72[cloudcat])); 411 if (cloudcat == 0) { 412 xpart = 0.0f; 413 } 414 cloudpart = cloudcat + xpart; 415 } 416 /* compute eye category */ 417 if ((eyetemp <= StormAODTInfo.ebd_v72[ixx]) 418 && (eyetemp > StormAODTInfo.ebd_v72[ixx + 1])) { 419 eyecat = ixx; 420 xpart = (float) ((eyetemp - StormAODTInfo.ebd_v72[eyecat]) / (StormAODTInfo.ebd_v72[eyecat + 1] - StormAODTInfo.ebd_v72[eyecat])); 421 if (eyecat == 0) { 422 xpart = 0.0f; 423 } 424 eyepart = eyecat + xpart; 425 } 426 /* compute C-W eye category */ 427 if ((cloudcwt <= StormAODTInfo.ebd_v72[ixx]) 428 && (cloudcwt > StormAODTInfo.ebd_v72[ixx + 1])) { 429 cwtcat = ixx; 430 xpart = (float) ((cloudcwt - StormAODTInfo.ebd_v72[cwtcat]) / (StormAODTInfo.ebd_v72[cwtcat + 1] - StormAODTInfo.ebd_v72[cwtcat])); 431 if (cwtcat == 0) { 432 xpart = 0.0f; 433 } 434 cwtpart = cwtcat + xpart; 435 } 436 } 437 438 /* printf("EYE = temp=%f cat=%d part=%f \n",eyetemp,eyecat,eyepart); */ 439 /* 440 * printf("CLD = temp=%f cat=%d part=%f \n",cloudtemp,cloudcat,cloudpart) 441 * ; 442 */ 443 /* printf("CWT = temp=%f cat=%d part=%f \n",cloudcwt,cwtcat,cwtpart); */ 444 diffcat = Math.max(0, Math.max(cloudcat, cwtcat) - eyecat); 445 diffcloudt = cloudtemp - cloudcwt; 446 diffeyecloudt = eyetemp - cloudtemp; 447 eyecwtcatdiff = cwtpart - eyepart; 448 eyecloudcatdiff = cloudpart - eyepart; 449 cloudcatdiff = cloudpart - cwtpart; 450 diffcloudcat = cloudcat - cwtcat; 451 diffeyecloudcat = cloudcat - eyecat; 452 diffcat2 = eyetemp - (Math.min(cloudtemp, cloudcwt)); 453 454 curtime = aodtv72_calctime(odtcurrent.date, odtcurrent.time); 455 curtimem12 = curtime - 0.5; 456 457 /* determine last Final T# value for curved band/other scene check */ 458 foundeye = false; 459 maxtno = 0.0f; 460 lastr9 = 0; 461 lasttno = maxtno; 462 lastvalidtno = lasttno; 463 if (true) { // (odthistoryfirst_v72==0)||(strlen(hfile_v72)==0)) { 464 foundm12 = true; 465 lastescene = 3; 466 lastr9 = 1; 467 if ((cwtpart < 3.5) && (osstr_v72 < 3.5)) { 468 lastcscene = 3; 469 lasttno12 = osstr_v72; 470 } else { 471 lastcscene = 0; 472 lasttno12 = Math.max(osstr_v72, 4.0f); 473 } 474 } /* 475 * else { odthistory=odthistoryfirst_v72; foundm12=FALSE; lastcscene=3; 476 * while(odthistory!=0) { 477 * xtime=aodtv72_calctime(odthistory->IR.date,odthistory->IR.time); 478 * landcheck=true; 479 * if(((oland_v72)&&(odthistory->IR.land==1))||(odthistory 480 * ->IR.Traw<1.0)) landcheck=FALSE; if((xtime<curtime)&&(landcheck)) { 481 * lastvalidtime=xtime; if((xtime>=curtimem12)&&(!foundm12)) { 482 * lasttno12=odthistory->IR.Tfinal; foundm12=true; } 483 * lasttno=odthistory->IR.Tfinal; lastcscene=odthistory->IR.cloudscene; 484 * lastescene=odthistory->IR.eyescene; if(lastescene<=2) foundeye=true; 485 * if((lastcscene==4)&&(lastescene==3)) foundeye=FALSE; 486 * lastvalidtno=lasttno; lastr9=odthistory->IR.rule9; if(lasttno>maxtno) 487 * maxtno=lasttno; } else { if(!landcheck) { 488 * 489 * if((xtime-lastvalidtime)>0.5) { foundeye=FALSE; 490 * lasttno=lastvalidtno-(1.0*(xtime-lastvalidtime)); 491 * 492 * } } } odthistory=odthistory->nextrec; } 493 * 494 * if(!foundm12) lasttno12=lasttno; } 495 */ 496 /* printf("foundm12=%d\n",foundm12); */ 497 /* printf("lasttno12=%f\n",lasttno12); */ 498 499 /* NEW SCENE IDENTIFICATION SCHEME */ 500 /* NEW EYE SCENE THRESHOLD DETERMINATION */ 501 Ec = 0.0f; 502 Ee = 0.0f; 503 Ea = 1.0f - ((eyefft - 2) * 0.1f); 504 Eb = -(eyepart * 0.5f); 505 if (eyestdv > 10.0) { 506 Ec = 0.50f; 507 } 508 /* Ed=eyecloudcatdiff*0.75; */ 509 Ed = (eyecloudcatdiff * 0.25f) + (eyecwtcatdiff * 0.50f); /* new */ 510 /* printf("Ed=%f\n",Ed); */ 511 /* printf("maxtno=%f Ee=%f\n",maxtno,Ee); */ 512 if ((foundm12) && (lastescene < 3) && (maxtno > 5.0)) { 513 Ee = Ee + 0.25f; 514 } 515 /* printf("Ee=%f\n",Ee); */ 516 /* if(lasttno12<3.5) Ee=Ee-1.0; */ 517 if (lasttno12 <= 4.5) { 518 Ee = Math.max(-1.0f, lasttno12 - 4.5f); /* new */ 519 } 520 /* printf("lasttno12=%f Ee=%f\n",lasttno12,Ee); */ 521 if ((lastr9 > 0) && (lasttno < 4.0)) { 522 Ee = Ee - 0.5f; /* new */ 523 } 524 /* printf("Ee=%f\n",Ee); */ 525 eyeval = Ea + Eb + Ec + Ed + Ee; 526 sceneeye = 3; /* NO EYE */ 527 if (eyeval >= 0.50) { 528 sceneeye = 0; /* EYE */ 529 } 530 /* 531 * if(eyeval>=0.00) sceneeye=5; / OBSCURED EYE / if(eyeval>=1.50) 532 * sceneeye=4; / RAGGED EYE / if(eyeval>=3.50) sceneeye=0; / CLEAR EYE / 533 */ 534 535 /* printf("eyeval= %f sceneeye=%d \n",eyeval,sceneeye); */ 536 float odtcurrent_v72IRRMW; 537 eyecdosize = 0.0f; 538 if (rmwsizeman > 0) { 539 /* printf("RMW SIZE=%d\n",rmwsizeman_v72); */ 540 odtcurrent_v72IRRMW = (float) rmwsizeman; 541 eyecdosize = (float) rmwsizeman - 1.0f; /* manually input eye size */ 542 } else { 543 float[] out = aodtv72_rmw(odtcurrent, areadata_v72); 544 rmw = out[0]; 545 eyecdosize = out[1]; 546 odtcurrent_v72IRRMW = rmw; 547 } 548 549 /* LARGE EYE CHECKS */ 550 if ((sceneeye == 0) && (eyecdosize >= 45.0)) { 551 sceneeye = 2; /* large eye */ 552 } 553 554 /* NEW CLOUD SCENE THRESHOLD DETERMINATION */ 555 shear = false; 556 irrcdo = false; 557 cbscene = true; 558 cbgray = true; 559 560 Cc = 0.0f; 561 Cd = 0.5f; /* changed to 0.5 */ 562 Ce = 0.0f; 563 Ca = cwtpart * 0.25f; 564 Cb = cloudpart * 0.25f; 565 if (cloudfft <= 2) { 566 Cc = Math.min(1.50f, cwtpart * 0.25f); 567 } 568 if (lastcscene >= 3) { 569 Cd = -0.50f; 570 } 571 /* printf("cwtpart=%f lasttno12=%f\n",cwtpart,lasttno12); */ 572 if (cwtpart > 2.0) { /* new */ 573 if (lasttno12 >= 2.5) { 574 if (sceneeye == 0) { 575 Ce = Math.min(1.00f, lasttno12 - 2.5f); 576 } 577 if (lasttno12 >= 3.5) { 578 Ce = Ce + 1.00f; 579 } 580 } 581 if ((foundm12) && (foundeye)) { 582 Ce = Ce + 1.25f; 583 } 584 } 585 cloudval = Ca + Cb + Cc + Cd + Ce; 586 if (cloudval < 0.0) { 587 shear = true; /* SHEAR */ 588 } 589 if (cloudval >= 0.00) { 590 cbscene = true; /* CURVED BAND (gray) */ 591 } 592 if (cloudval >= 1.00) { 593 cbscene = true; /* CURVED BAND (gray) */ 594 /* check for irregular CDO */ 595 if ((diffcat2 < 0.0) && (cloudsyma > 40.0)) { 596 irrcdo = true; /* IRREGULAR CDO */ 597 } 598 } 599 if ((cloudval >= 2.00) && (cloudval < 3.00)) { 600 cbscene = true; /* CURVED BAND (gray) */ 601 /* check for irregular CDO */ 602 /* if((diffcloudcat<0)&&(diffcloudt>8.0)&&(cloudsyma>30.0)) { */ 603 if ((diffcat2 < 0.0) && (cloudsyma > 30.0)) { 604 irrcdo = true; /* IRREGULAR CDO */ 605 } 606 if (cwtcat >= 3) { 607 /* if xcwt>3.0 try black/white CB check */ 608 if ((diffcloudcat > 0) && (diffcloudt < -8.0)) { 609 cbgray = false; /* CURVED BAND (black/white) */ 610 } 611 /* check for large/ragged eye */ 612 if ((sceneeye == 0) 613 || ((eyepart > 1.00) && (diffeyecloudcat >= 2.00))) { 614 cbscene = false; /* EYE */ 615 } 616 /* check for CDO */ 617 if ((cloudcatdiff <= 0.0) && (eyecwtcatdiff < 1.00)) { 618 cbscene = false; /* CDO */ 619 } 620 } 621 } 622 if (cloudval >= 3.00) { 623 cbscene = false; /* CDO */ 624 /* check for irregular CDO */ 625 if ((diffcloudcat < 0) && (diffcloudt > 8.0) && (cloudsyma > 30.0)) { 626 irrcdo = true; /* IRREGULAR CDO */ 627 cbscene = true; 628 } 629 } 630 /* EMBEDDED CENTER CHECK */ 631 if ((cloudtemp < cloudcwt) && (cloudcwt < eyetemp)) { 632 checkembc = true; 633 } 634 if ((!cbscene) && (checkembc)) { 635 tempval = (float) StormAODTInfo.ebd_v72[cwtcat + 1] + 273.16f; 636 float[] out = aodtv72_logspiral(xlat, xlon, tempval, 1, odtcurrent, 637 areadata_v72); 638 spiral = (int) out[0]; 639 if ((spiral >= 8) && (spiral < 20)) { 640 embdd = true; 641 } 642 /* printf(" EMBDD : cwtcat=%d spiral=%d \n",cwtcat,spiral); */ 643 } 644 645 /* 646 * printf("cloudval= %f shear=%d cbscene=%d cbgray=%d irrcdo=%d \n",cloudval 647 * ,shear,cbscene,cbgray,irrcdo); 648 */ 649 // (void)aodtv72_julian2cmonth(odtcurrent_v72IR.date,cdate); 650 /* 651 * printf("%9s %6d %4.1f %4.1f %2d %2d %5.1f %5.1f %5.2f %5.2f %5.2f 652 * %5.2f %5.2f %5.2f %5.2f %2d %2d %4.1f %4.1f %5.2f %5.2f %5.2f %5.2f 653 * %5.2f %5.2f %6.2f %7.2f %3.1f \n",cdate,odtcurrent_v72->IR.time, 654 * cloudpart 655 * ,cwtpart,cloudfft,diffcloudcat,diffcloudt,cloudsyma,Ca,Cb,0.0 656 * ,Cc,Cd,Ce,cloudval, 657 * eyefft,diffeyecloudcat,eyepart,eyestdv,Ea,Eb,Ec,Ed 658 * ,Ee,eyeval,xlat,xlon,lasttno); 659 */ 660 661 /* CLASSIFY CLOUD REGION */ 662 cbring = 0; 663 cbringval = 0; 664 cbringvalmax = 0; 665 cbringlatmax = xlat; 666 cbringlonmax = xlon; 667 668 // L100: 669 if (cbscene) { 670 if (shear) { 671 sceneeye = 3; /* NO EYE */ 672 scenecloud = 4; /* SHEAR */ 673 tempval = (float) StormAODTInfo.ebd_v72[3] + 273.16f; 674 float[] out = aodtv72_cdoshearcalc(xlat, xlon, tempval, 3, 675 areadata_v72); 676 eyecdosize = Math.max(4.0f, out[0]); 677 } else if (irrcdo) { 678 sceneeye = 3; /* NO EYE */ 679 scenecloud = 2; /* IRREGULAR CDO */ 680 } else { 681 cbfound = false; 682 // L200: 683 if (cbgray) { 684 /* perform Curved Band analysis */ 685 ixx = 4; /* start with LIGHT GRAY */ 686 while ((ixx >= 2) && (!cbfound)) { 687 tempval = (float) StormAODTInfo.ebd_v72[ixx] + 273.16f; 688 float[] out0 = aodtv72_logspiral(xlat, xlon, tempval, 689 1, odtcurrent, areadata_v72); 690 spiral = (int) out0[0]; 691 /* printf("BD level=%d spiral=%d\n",ixx,spiral); */ 692 if ((out0[0] >= 8) || (ixx == 2)) { /* 693 * 10 = .375% -- 10 694 * ==> 9 arcs of 15 695 * degrees 696 */ 697 if (spiral > 25) { 698 if (ixx == 4) { 699 cbgray = false; 700 // goto L200; 701 cbscene = false; 702 ixx = 6; 703 while ((ixx > 4) && (!cbfound)) { 704 tempval = (float) StormAODTInfo.ebd_v72[ixx] + 273.16f; 705 float[] out = aodtv72_logspiral(xlat, 706 xlon, tempval, 1, odtcurrent, 707 areadata_v72); 708 spiral = (int) out[0]; 709 if ((spiral >= 9) && (spiral <= 25)) { 710 cbfound = true; 711 } else { 712 ixx--; 713 } 714 } 715 } else { 716 ixx = 0; 717 } 718 } else { 719 if ((ixx == 2) && (spiral < 7)) { /* 720 * 7 = .25% -- 721 * 10 ==> 6 arcs 722 * of 15 degrees 723 */ 724 /* probably shear */ 725 cbfound = false; 726 shear = true; 727 // goto L100; 728 sceneeye = 3; /* NO EYE */ 729 scenecloud = 4; /* SHEAR */ 730 tempval = (float) StormAODTInfo.ebd_v72[3] + 273.16f; 731 float[] out = aodtv72_cdoshearcalc(xlat, 732 xlon, tempval, 3, areadata_v72); 733 eyecdosize = Math.max(4.0f, out[0]); 734 } else { 735 cbfound = true; 736 } 737 } 738 } else { 739 ixx--; 740 } 741 } 742 } else { 743 /* try BLACK and WHITE rings */ 744 cbscene = false; 745 ixx = 6; 746 while ((ixx > 4) && (!cbfound)) { 747 tempval = (float) StormAODTInfo.ebd_v72[ixx] + 273.16f; 748 float[] out = aodtv72_logspiral(xlat, xlon, tempval, 1, 749 odtcurrent, areadata_v72); 750 spiral = (int) out[0]; 751 if ((spiral >= 9) && (spiral <= 25)) { 752 cbfound = true; 753 } else { 754 ixx--; 755 } 756 } 757 } 758 if (cbfound) { 759 /* found curved band scenes */ 760 cbring = ixx; 761 cbringval = spiral; 762 sceneeye = 3; /* NO EYE */ 763 scenecloud = 3; /* CURVED BAND */ 764 /* 765 * search for maximum curved band analysis location within 766 * 1-degree box 767 */ 768 tempval = (float) StormAODTInfo.ebd_v72[cbring] + 273.16f; 769 if (osearch_v72) { 770 float[] out = aodtv72_logspiral(xlat, xlon, tempval, 2, 771 odtcurrent, areadata_v72); 772 spiralmax = (int) out[0]; 773 lat2 = out[1]; 774 lon2 = out[2]; 775 776 cbringvalmax = (int) out[0]; 777 cbringlatmax = out[1]; 778 cbringlonmax = out[2]; 779 } 780 } else { 781 /* 782 * did not find curved band scenes, mark as non-eye/eye 783 * scene 784 */ 785 scenecloud = 0; 786 cbscene = false; 787 embdd = false; /* redundant declaration */ 788 // goto L100; 789 scenecloud = 0; /* UNIFORM */ 790 if (embdd) { 791 scenecloud = 1; /* EMBEDDED CENTER */ 792 } 793 /* PINHOLE EYE TEST */ 794 /* 795 * printf("sceneeye=%d diffeyecloudcat=%d eyefft=%d cwtpart=%f scenecloud=%d cloudfft=%d lasttno12=%f\n" 796 * , 797 * sceneeye,diffeyecloudcat,eyefft,cwtpart,scenecloud,cloudfft 798 * ,lasttno12); 799 */ 800 if ((rmwsizeman > 0) && (rmwsizeman < 5.0)) { 801 sceneeye = 1; 802 } 803 if ((eyeval > -0.25) && (eyeval < 1.50) 804 && (diffeyecloudcat >= 2) && (eyefft <= 2) 805 && (cwtpart > 6.0) && (scenecloud <= 1) 806 && (cloudfft <= 4) && (lasttno12 >= 3.5)) { 807 sceneeye = 1; /* PINHOLE EYE CHECK */ 808 } 809 } 810 } 811 } else { 812 scenecloud = 0; /* UNIFORM */ 813 if (embdd) { 814 scenecloud = 1; /* EMBEDDED CENTER */ 815 } 816 /* PINHOLE EYE TEST */ 817 /* 818 * printf("sceneeye=%d diffeyecloudcat=%d eyefft=%d cwtpart=%f scenecloud=%d cloudfft=%d lasttno12=%f\n" 819 * , 820 * sceneeye,diffeyecloudcat,eyefft,cwtpart,scenecloud,cloudfft,lasttno12 821 * ); 822 */ 823 if ((rmwsizeman > 0) && (rmwsizeman < 5.0)) { 824 sceneeye = 1; 825 } 826 if ((eyeval > -0.25) && (eyeval < 1.50) && (diffeyecloudcat >= 2) 827 && (eyefft <= 2) && (cwtpart > 6.0) && (scenecloud <= 1) 828 && (cloudfft <= 4) && (lasttno12 >= 3.5)) { 829 sceneeye = 1; /* PINHOLE EYE CHECK */ 830 } 831 } 832 if ((scenecloud <= 2) && (sceneeye == 3)) { 833 /* for CDO TESTS */ 834 for (ixx = 2; ixx <= 6; ixx++) { /* DG,MG,LG,B,W */ 835 tempval = (float) StormAODTInfo.ebd_v72[ixx] + 273.16f; 836 /* printf("xlat=%f xlon=%f tempval=%f\n",xlat,xlon,tempval); */ 837 float[] out = aodtv72_cdoshearcalc(xlat, xlon, tempval, 1, 838 areadata_v72); 839 /* 840 * printf("CDO : ixx=%d cdosize=%f cdosize/111=%f \n",ixx,cdosize 841 * ,cdosize/111.0); 842 */ 843 if (ixx == 2) { 844 eyecdosize = out[0]; 845 } 846 } 847 } 848 849 /* 850 * odtcurrent_v72IR.eyescene=sceneeye; 851 * odtcurrent_v72IR.cloudscene=scenecloud; 852 * odtcurrent_v72IR.eyesceneold=-1; odtcurrent_v72IR.cloudsceneold=-1; 853 * odtcurrent_v72IR.eyecdosize=eyecdosize; 854 * odtcurrent_v72IR.ringcb=cbring; odtcurrent_v72IR.ringcbval=cbringval; 855 * odtcurrent_v72IR.ringcbvalmax=cbringvalmax; 856 * odtcurrent_v72IR.ringcblatmax=cbringlatmax; 857 * odtcurrent_v72IR.ringcblonmax=cbringlonmax; 858 */ 859 float[] odt = { sceneeye, scenecloud, eyecdosize, cbring, cbringval, 860 cbringvalmax, cbringlatmax, cbringlonmax, odtcurrent_v72IRRMW, 861 alst, Aaveext, Estdveye, Aavesym, eyecnt, rngcnt }; 862 863 return odt; 864 865 } 866 867 /** 868 * 869 * @param odtcurrent 870 * @param areadata 871 * @return 872 */ 873 874 static float[] aodtv72_rmw(StormAODTInfo.IRData odtcurrent, 875 StormAODTInfo.DataGrid areadata) 876 /* 877 * Determine radius of maximum wind based upon Jim Kossin's regression based 878 * scheme Inputs : ix0 - element location of center point iy0 - line 879 * location of center point Outputs : rmw - radius of maximum wind distance 880 * eyesize - eye size radius (km) -1 = error/eyewall not found 0 = radius 881 * found 882 */ 883 { 884 int ixmin, ixmax, iymin, iymax; 885 int ixc, iyc, i, ix, iy, idx1 = 0, idy1 = 0, idx2 = 0, idy2 = 0; 886 float dx1, dx2, dy1, dy2, dav, xlat, xlon, xclat, xclon, xangle; 887 float tcrit = 228.0f, warm = 223.0f; 888 float rmw; 889 float eyesize; 890 891 /* 892 * calculate cursorx/cursory from numx/numy... values should be 893 * 0.5*numx/y 894 */ 895 ixc = areadata.numx / 2; 896 iyc = areadata.numy / 2; 897 ixmax = Math.min(areadata.numx, ixc + 320); 898 ixmin = Math.max(0, ixc - 320); 899 iymax = Math.min(areadata.numy, iyc + 240); 900 iymin = Math.max(0, iyc - 240); 901 902 if (odtcurrent.cloudt >= warm) { 903 tcrit = (odtcurrent.eyet + (2.0f * odtcurrent.cloudt)) / 3.0f; 904 } 905 906 rmw = -99.9f; 907 eyesize = -99.9f; 908 /* iterate five times */ 909 for (i = 0; i < 5; i++) { 910 ix = ixc; 911 while (areadata.temp[iyc][ix] > tcrit) { 912 ix = ix - 1; 913 if (ix == ixmin) { 914 return null; 915 } 916 } 917 idx1 = ix; 918 ix = ixc; 919 while (areadata.temp[iyc][ix] > tcrit) { 920 ix = ix + 1; 921 if (ix == ixmax) { 922 return null; 923 } 924 } 925 idx2 = ix; 926 iy = iyc; 927 while (areadata.temp[iy][ixc] > tcrit) { 928 iy = iy - 1; 929 if (iy == iymin) { 930 return null; 931 } 932 } 933 idy1 = iy; 934 iy = iyc; 935 while (areadata.temp[iy][ixc] > tcrit) { 936 iy = iy + 1; 937 if (iy == iymax) { 938 return null; 939 } 940 } 941 idy2 = iy; 942 ixc = (int) ((((float) (idx1 + idx2)) / 2.0)); 943 iyc = (int) ((((float) (idy1 + idy2)) / 2.0)); 944 } 945 xclat = areadata.lat[iyc][ixc]; 946 xclon = areadata.lon[iyc][ixc]; 947 xlat = areadata.lat[iyc][idx1]; 948 xlon = areadata.lon[iyc][idx1]; 949 float[] out = aodtv72_distance(xlat, xlon, xclat, xclon, 1); 950 dx1 = out[0]; 951 952 xlat = areadata.lat[iyc][idx2]; 953 xlon = areadata.lon[iyc][idx2]; 954 out = aodtv72_distance(xlat, xlon, xclat, xclon, 1); 955 dx2 = out[0]; 956 xlat = areadata.lat[idy1][ixc]; 957 xlon = areadata.lon[idy1][ixc]; 958 out = aodtv72_distance(xlat, xlon, xclat, xclon, 1); 959 dy1 = out[0]; 960 961 xlat = areadata.lat[idy2][ixc]; 962 xlon = areadata.lon[idy2][ixc]; 963 out = aodtv72_distance(xlat, xlon, xclat, xclon, 1); 964 dy2 = out[0]; 965 966 dav = (dx1 + dx2 + dy1 + dy2) / 4.0f; 967 if (dav > 0.0) { 968 rmw = 2.8068f + (0.8361f * dav); /* Howard's coeffs */ 969 eyesize = dav; 970 } 971 float[] outf = { rmw, eyesize }; 972 973 return outf; 974 } 975 976 /** 977 * 978 * @param inlat 979 * @param inlon 980 * @param searchtemp 981 * @param searchtype 982 * @param odtcurrent_v72IR 983 * @param areadata_v72 984 * @return 985 */ 986 static float[] aodtv72_logspiral(float inlat, float inlon, 987 float searchtemp, int searchtype, 988 StormAODTInfo.IRData odtcurrent_v72IR, 989 StormAODTInfo.DataGrid areadata_v72) 990 /* 991 * Determine storm location using 10^ Log-spiral analysis. Algorithm will 992 * attempt to match the spiral with the image pixels at or below the 993 * threshold temperature based on BD-enhancement curve values Inputs : inlat 994 * - center latitude of analysis grid inlon - center longitude of analysis 995 * grid searchtemp - temperature threshold value searchtype - 1=search at 996 * single point;2=search over 2^box Outputs : bestlat - best latitude 997 * location from analysis bestlon - best longitude location from analysis 998 * bestspiral - number of consecutive arcs through which spiral passes 999 */ 1000 { 1001 1002 int ixx, iyy, izz, iskip, rotfac = 0, theta, b; 1003 int imaxx, iminx, imaxy, iminy, ycount; 1004 int spiralconsec, maxconsec, spiralbest, spiralbestrot, bestrot = 0; 1005 float xrad = 57.29578f, A = 25.0f, B = 10.0f / xrad; 1006 float maxx, minx, maxy, miny, xmindist; 1007 float xlat = 0.f, xlon = 0.f; 1008 float ylatdiff, ylondiff, xres = 6.0f; 1009 float thetax, r, thetaval, thetaval2; 1010 /* float zlat[bufsiz],zlon[bufsiz]; */ 1011 float[] zlat, zlon, lres; 1012 int np, ipt; 1013 int bestspiral; 1014 float bestlat = 0.f; 1015 float bestlon = 0.f; 1016 1017 if (odtcurrent_v72IR.sattype == 5) { 1018 xres = 12.0f; 1019 } 1020 /* allocate memory */ 1021 int nn = areadata_v72.numx * areadata_v72.numy; 1022 zlat = new float[nn]; 1023 zlon = new float[nn]; 1024 1025 if (searchtype == 2) { 1026 /* search over 2.0 degree box */ 1027 maxx = inlat + 1.0f; 1028 minx = inlat - 1.0f; 1029 maxy = inlon + 1.0f; 1030 miny = inlon - 1.0f; 1031 imaxx = (int) (maxx * 100.0); 1032 iminx = (int) (minx * 100.0); 1033 imaxy = (int) (maxy * 100.0); 1034 iminy = (int) (miny * 100.0); 1035 } else { 1036 /* search at a single point */ 1037 imaxx = (int) (inlat * 100.0); 1038 iminx = (int) (inlat * 100.0); 1039 imaxy = (int) (inlon * 100.0); 1040 iminy = (int) (inlon * 100.0); 1041 } 1042 1043 bestspiral = 0; 1044 1045 /* initialize arrays */ 1046 np = 0; 1047 for (ixx = 0; ixx < areadata_v72.numx; ixx++) { 1048 for (iyy = 0; iyy < areadata_v72.numy; iyy++) { 1049 if (areadata_v72.temp[iyy][ixx] <= searchtemp) { 1050 zlat[np] = areadata_v72.lat[iyy][ixx]; 1051 zlon[np] = areadata_v72.lon[iyy][ixx]; 1052 np++; 1053 } 1054 } 1055 } 1056 1057 /* loop through x-axis/elements of analysis grid box */ 1058 for (ixx = iminx; ixx <= imaxx; ixx = ixx + 20) { 1059 xlat = (float) ixx / 100.0f; 1060 /* loop through y-axis/lines of analysis grid box */ 1061 for (iyy = iminy; iyy <= imaxy; iyy = iyy + 20) { 1062 xlon = (float) iyy / 100.0f; 1063 iskip = 0; 1064 /* determine distance from each point in box to current location */ 1065 if (searchtype == 2) { 1066 xmindist = 12.0f; 1067 for (izz = 0; izz < np; izz++) { 1068 float[] out3 = aodtv72_distance(xlat, xlon, zlat[izz], 1069 zlon[izz], 1); 1070 if (out3[0] <= xmindist) { 1071 /* 1072 * if the lat/lon point is too close to cold cloud 1073 * tops, do not calculate log spiral at this point. 1074 * Trying to eliminate "false" arc locations by 1075 * forcing the system to use some of the arc points 1076 * on the spiral away from the start of the spiral 1077 * (were getting "false echos" without this". 1078 */ 1079 iskip = 1; 1080 break; 1081 } 1082 } 1083 } 1084 1085 spiralbest = 0; 1086 spiralbestrot = 0; 1087 /* 1088 * if arc location passes analysis above, proceed with placement 1089 * of spiral 1090 */ 1091 if (iskip == 0) { 1092 /* 1093 * rotate the arc spiral thru entire revolution at 30 degree 1094 * intervals 1095 */ 1096 for (rotfac = 0; rotfac <= 330; rotfac = rotfac + 30) { 1097 spiralconsec = 0; 1098 maxconsec = 0; 1099 1100 /* 1101 * calculate position of each point on spiral from 0 to 1102 * 540^ 1103 */ 1104 for (theta = 0; theta <= 540; theta = theta + 15) { 1105 thetax = (float) theta / xrad; 1106 r = A * (float) Math.exp((B * thetax)); 1107 thetaval = (float) theta + (float) rotfac; 1108 if (xlat < 0.0) { 1109 thetaval = (float) (-1 * theta) 1110 + (float) rotfac; 1111 } 1112 thetaval2 = thetaval + 180.0f; 1113 float[] out2 = aodtv72_distance2(xlat, xlon, r, 1114 thetaval2); 1115 ycount = 0; 1116 for (izz = 0; izz < np; izz++) { 1117 ylatdiff = Math.abs(out2[0] - zlat[izz]); 1118 ylondiff = Math.abs(out2[1] - zlon[izz]); 1119 /* 1120 * if a point is within 0.1^ latitude/longitude 1121 * determine distance 1122 */ 1123 if ((ylatdiff <= 0.1) && (ylondiff <= 0.1)) { 1124 float[] out3 = aodtv72_distance(out2[0], 1125 out2[1], zlat[izz], zlon[izz], 1); 1126 /* 1127 * if distance from spiral point is within 1128 * 6km from an accepted temperature 1129 * threshold point, count it 1130 */ 1131 if (out3[0] <= xres) { 1132 ycount++; 1133 } 1134 } 1135 } 1136 /* 1137 * if there are 4 or more threshold points 1138 * associated with each spiral point, count within 1139 * consecutive spiral point counter 1140 */ 1141 if (ycount >= 4) { 1142 spiralconsec++; 1143 /* 1144 * save spiral that has the maximum consecutive 1145 * spiral counts for each rotation though 360^ 1146 * at each center location 1147 */ 1148 if (spiralconsec > maxconsec) { 1149 maxconsec = spiralconsec; 1150 } 1151 } else { 1152 spiralconsec = 0; 1153 } 1154 /* 1155 * if this spiral has the greatest number of 1156 * consecutive spiral points, save the location and 1157 * number of points 1158 */ 1159 if (maxconsec > spiralbest) { 1160 spiralbest = maxconsec; 1161 spiralbestrot = rotfac; 1162 } 1163 } 1164 } /* rotfac loop */ 1165 if (spiralbest > bestspiral) { 1166 bestspiral = spiralbest; 1167 bestlat = xlat; 1168 bestlon = xlon; 1169 bestrot = spiralbestrot; 1170 } 1171 } /* iskip if */ 1172 } /* iyy loop */ 1173 } /* ixx loop */ 1174 1175 /* free memory */ 1176 1177 /* load array for best spiral band */ 1178 ipt = 0; 1179 for (theta = 0; theta <= 540; theta = theta + 15) { 1180 thetax = (float) theta / xrad; 1181 r = A * (float) Math.exp((B * thetax)); 1182 thetaval = (float) theta + (float) bestrot; 1183 if (xlat < 0.0) { 1184 thetaval = (float) (-1 * theta) + (float) rotfac; 1185 } 1186 thetaval2 = thetaval + 180.0f; 1187 float[] out2 = aodtv72_distance2(bestlat, bestlon, r, thetaval2); 1188 /* load array for external plotting of spiral band */ 1189 // spiralband_v72[0][ipt]=out2[0]; 1190 // spiralband_v72[1][ipt]=out2[1]; 1191 ipt++; 1192 } 1193 1194 float[] out = { bestspiral, bestlat, bestlon }; 1195 return out; 1196 1197 } 1198 1199 /** 1200 * _more_ 1201 * 1202 * @param bin 1203 * _more_ 1204 * @param nbin 1205 * _more_ 1206 * 1207 * @return _more_ 1208 */ 1209 static float[] aodtv72_calcskew(float[] bin, int nbin) 1210 /* 1211 * Calculate average, standard deviation, and skew for a given data set. 1212 * Inputs : bin - data array nbin - number of points in data array Outputs : 1213 * ave - average value in array stdv - standard deviation of data array skew 1214 * - skew of data array histogram 1215 */ 1216 { 1217 int ixx; 1218 float xave, xstdv, xskew; 1219 float a2sum = 0.0f, a3sum = 0.0f, nsum = 0.0f; 1220 float ave, stdv, skew; 1221 1222 for (ixx = 0; ixx < nbin; ixx++) { 1223 nsum = nsum + bin[ixx]; 1224 } 1225 /* compute average value of data array */ 1226 xave = nsum / (float) nbin; 1227 1228 for (ixx = 0; ixx < nbin; ixx++) { 1229 a2sum = a2sum + ((bin[ixx] - xave) * (bin[ixx] - xave)); 1230 a3sum = a3sum 1231 + ((bin[ixx] - xave) * (bin[ixx] - xave) * (bin[ixx] - xave)); 1232 } 1233 if (nbin <= 1) { 1234 xstdv = 0.0f; 1235 xskew = 0.0f; 1236 } else { 1237 /* calculate standard deviation of data array */ 1238 xstdv = (float) Math.sqrt((1.0f / ((float) nbin - 1.0f)) * a2sum); 1239 /* calculate skew of data array */ 1240 xskew = (float) ((1.0f / ((float) nbin - 1.0f)) * a3sum) 1241 / (xstdv * xstdv * xstdv); 1242 } 1243 1244 /* return desired values */ 1245 ave = xave; 1246 stdv = xstdv; 1247 skew = xskew; 1248 float[] out = { ave, stdv, skew }; 1249 return out; 1250 } 1251 1252 /** 1253 * _more_ 1254 * 1255 * @param x1 1256 * _more_ 1257 * @param x2 1258 * _more_ 1259 * @param i2 1260 * _more_ 1261 * @param ndim 1262 * _more_ 1263 */ 1264 static void aodtv72_xxsort(float[] x1, float[] x2, float[] i2, int ndim) { 1265 int ih, i; 1266 float x, top; 1267 1268 ih = aodtv72_fminx(x1); 1269 x = x1[ih]; 1270 top = x - 1.0f; 1271 for (i = 0; i < ndim; i++) { 1272 ih = aodtv72_fmaxx(x1); 1273 i2[i] = ih; 1274 x2[i] = x1[ih]; 1275 x1[ih] = top; 1276 } 1277 } 1278 1279 /** 1280 * _more_ 1281 * 1282 * @param f 1283 * _more_ 1284 * 1285 * @return _more_ 1286 */ 1287 static int aodtv72_fminx(float[] f) { 1288 int i; 1289 int im; 1290 int ndim = f.length; 1291 float x; 1292 1293 im = 0; 1294 x = f[0]; 1295 for (i = 1; i < ndim; i++) { 1296 if (f[i] < x) { 1297 x = f[i]; 1298 im = i; 1299 } 1300 } 1301 return im; 1302 } 1303 1304 /** 1305 * _more_ 1306 * 1307 * @param f 1308 * _more_ 1309 * 1310 * @return _more_ 1311 */ 1312 static int aodtv72_fmaxx(float[] f) { 1313 int i; 1314 int im; 1315 int ndim = f.length; 1316 float x; 1317 1318 im = 0; 1319 x = f[0]; 1320 for (i = 1; i < ndim; i++) { 1321 if (f[i] > x) { 1322 x = f[i]; 1323 im = i; 1324 } 1325 } 1326 return im; 1327 } 1328 1329 /** 1330 * _more_ 1331 * 1332 * @param cbd 1333 * _more_ 1334 * 1335 * @return _more_ 1336 */ 1337 static float[] aodtv72_fft(float[] cbd) { 1338 int ixx, idxc, iok; 1339 double[] xr, xi, magn; 1340 double dx, a, x; 1341 float dx2; 1342 int idxcnt; 1343 1344 xr = new double[64]; 1345 xi = new double[64]; 1346 magn = new double[64]; 1347 /* initialize arrays */ 1348 for (ixx = 1; ixx <= 64; ++ixx) { 1349 xr[ixx - 1] = cbd[ixx - 1]; 1350 xi[ixx - 1] = (float) 0.; 1351 magn[ixx - 1] = (float) 0.; 1352 } 1353 /* call FFT routine */ 1354 iok = aodtv72_dfft(xr, xi, 64); 1355 if (iok <= 0) { 1356 return null; 1357 } 1358 for (ixx = 1; ixx <= 64; ++ixx) { 1359 magn[ixx - 1] = aodtv72_cmplx_abs(xr[ixx - 1], xi[ixx - 1]); 1360 } 1361 /* compute number of harmonics and magnitude of main harmonic */ 1362 dx = (float) 0.; 1363 idxc = 0; 1364 for (ixx = 2; ixx <= 31; ++ixx) { 1365 a = magn[ixx - 2]; 1366 x = magn[ixx - 1]; 1367 dx += (x + a) / (float) 2.; 1368 if ((magn[ixx - 1] > magn[ixx - 2]) && (magn[ixx - 1] > magn[ixx])) { 1369 ++idxc; 1370 } 1371 } 1372 dx2 = (float) (dx / magn[0]); 1373 1374 idxcnt = idxc; 1375 1376 float[] out = { dx2, idxcnt }; 1377 1378 return out; 1379 1380 } /* MAIN__ */ 1381 1382 /** 1383 * _more_ 1384 * 1385 * @param real 1386 * _more_ 1387 * @param imag 1388 * _more_ 1389 * 1390 * @return _more_ 1391 */ 1392 static double aodtv72_cmplx_abs(double real, double imag) { 1393 double temp; 1394 if (real < 0) { 1395 real = -real; 1396 } 1397 if (imag < 0) { 1398 imag = -imag; 1399 } 1400 if (imag > real) { 1401 temp = real; 1402 real = imag; 1403 imag = temp; 1404 } 1405 if ((real + imag) == real) { 1406 return (real); 1407 } 1408 1409 temp = imag / real; 1410 temp = real * Math.sqrt(1.0 + temp * temp); /* overflow!! */ 1411 return (temp); 1412 1413 } 1414 1415 /* 1416 * A Duhamel-Hollman split-radix dif fft Ref: Electronics Letters, Jan. 5, 1417 * 1984 Complex input and output data in arrays x and y Length is n. 1418 */ 1419 1420 /** 1421 * _more_ 1422 * 1423 * @param x 1424 * _more_ 1425 * @param y 1426 * _more_ 1427 * @param np 1428 * _more_ 1429 * 1430 * @return _more_ 1431 */ 1432 static int aodtv72_dfft(double[] x, double[] y, int np) { 1433 1434 int i, j, k, m, n, i0, i1, i2, i3, is, id, n1, n2, n4; 1435 double a, e, a3, cc1, ss1, cc3, ss3, r1, r2, s1, s2, s3, xt; 1436 1437 double px[] = { 0, x[0] }; 1438 double py[] = { 0, y[0] }; 1439 1440 for (i = 0; i < 2; i++) { 1441 px[i] = x[i] - 1; 1442 py[i] = y[i] - 1; 1443 } 1444 1445 i = 2; 1446 m = 1; 1447 1448 while (i < np) { 1449 i = i + i; 1450 m = m + 1; 1451 } 1452 ; 1453 n = i; 1454 if (n != np) { 1455 for (i = np + 1; i <= n; i++) { 1456 px[i] = 0.0; 1457 py[i] = 0.0; 1458 } 1459 /* printf("\nuse %d point fft",n); */ 1460 } 1461 1462 n2 = n + n; 1463 for (k = 1; k <= m - 1; k++) { 1464 n2 = n2 / 2; 1465 n4 = n2 / 4; 1466 e = 2.0 * PI / n2; 1467 a = 0.0; 1468 for (j = 1; j <= n4; j++) { 1469 a3 = 3.0 * a; 1470 cc1 = Math.cos(a); 1471 ss1 = Math.sin(a); 1472 cc3 = Math.cos(a3); 1473 ss3 = Math.sin(a3); 1474 a = j * e; 1475 is = j; 1476 id = 2 * n2; 1477 while (is < n) { 1478 for (i0 = is; i0 <= n - 1; i0 = i0 + id) { 1479 i1 = i0 + n4; 1480 i2 = i1 + n4; 1481 i3 = i2 + n4; 1482 r1 = px[i0] - px[i2]; 1483 px[i0] = px[i0] + px[i2]; 1484 r2 = px[i1] - px[i3]; 1485 px[i1] = px[i1] + px[i3]; 1486 s1 = py[i0] - py[i2]; 1487 py[i0] = py[i0] + py[i2]; 1488 s2 = py[i1] - py[i3]; 1489 py[i1] = py[i1] + py[i3]; 1490 s3 = r1 - s2; 1491 r1 = r1 + s2; 1492 s2 = r2 - s1; 1493 r2 = r2 + s1; 1494 px[i2] = r1 * cc1 - s2 * ss1; 1495 py[i2] = -s2 * cc1 - r1 * ss1; 1496 px[i3] = s3 * cc3 + r2 * ss3; 1497 py[i3] = r2 * cc3 - s3 * ss3; 1498 } 1499 is = 2 * id - n2 + j; 1500 id = 4 * id; 1501 } 1502 } 1503 } 1504 1505 /* 1506 * ---------------------Last stage, length=2 1507 * butterfly--------------------- 1508 */ 1509 is = 1; 1510 id = 4; 1511 while (is < n) { 1512 for (i0 = is; i0 <= n; i0 = i0 + id) { 1513 i1 = i0 + 1; 1514 r1 = px[i0]; 1515 px[i0] = r1 + px[i1]; 1516 px[i1] = r1 - px[i1]; 1517 r1 = py[i0]; 1518 py[i0] = r1 + py[i1]; 1519 py[i1] = r1 - py[i1]; 1520 } 1521 is = 2 * id - 1; 1522 id = 4 * id; 1523 } 1524 1525 /* 1526 * c--------------------------Bit reverse counter 1527 */ 1528 j = 1; 1529 n1 = n - 1; 1530 for (i = 1; i <= n1; i++) { 1531 if (i < j) { 1532 xt = px[j]; 1533 px[j] = px[i]; 1534 px[i] = xt; 1535 xt = py[j]; 1536 py[j] = py[i]; 1537 py[i] = xt; 1538 } 1539 k = n / 2; 1540 while (k < j) { 1541 j = j - k; 1542 k = k / 2; 1543 } 1544 j = j + k; 1545 } 1546 1547 /* 1548 * for (i = 1; i<=16; i++) printf("%d %g %gn",i,*(px+i),(py+i)); 1549 */ 1550 1551 return (n); 1552 } 1553 1554 /** 1555 * _more_ 1556 * 1557 * @param keyer 1558 * _more_ 1559 * @param areadata 1560 * _more_ 1561 * 1562 * @return _more_ 1563 */ 1564 static public StormAODTInfo.IRData aodtv72_gettemps(int keyer, 1565 StormAODTInfo.DataGrid areadata) 1566 /* 1567 * Determine eye and coldest-warmest cloud temperatures. Inputs : keyer - 1568 * eye radius (km) Outputs : odtcurrent_v72 - structure containing current 1569 * image information Return : -51 : eye, cloud, or warmest temperature 1570 * <-100C or >+40C 1571 */ 1572 { 1573 1574 int cursorx, cursory; 1575 int iok, idist, iret; 1576 float cursortemp, eyet, cloudt; 1577 float cursorlat, cursorlon, warmlat, warmlon, eyeangle, eyedist; 1578 StormAODTInfo sinfo = new StormAODTInfo(); 1579 StormAODTInfo.IRData odtcurrent = sinfo.new IRData(); 1580 1581 /* 1582 * calculate cursorx/cursory from numx/numy... values should be 1583 * 0.5*numx/y 1584 */ 1585 cursorx = areadata.numx / 2; 1586 cursory = areadata.numy / 2; 1587 cursortemp = areadata.temp[cursory][cursorx]; 1588 cursorlat = areadata.lat[cursory][cursorx]; 1589 cursorlon = areadata.lon[cursory][cursorx]; 1590 1591 // tcircfirst_v72=(struct ringdata *)calloc(1,sizeof(struct ringdata)); 1592 1593 /* load array containing data on rings around center location */ 1594 List<StormAODTInfo.RingData> tcircfirst = aodtv72_readcirc(cursorx, 1595 cursory, areadata); 1596 1597 iret = 0; 1598 /* compute eye/warmest pixel temperature */ 1599 StormAODTInfo.RingData eye = aodtv72_calceyetemp(keyer, cursortemp, 1600 tcircfirst); 1601 eyet = eye.temp; 1602 if ((eyet < -100.0) || (eyet > 40.0)) { 1603 iret = -51; 1604 } 1605 1606 if (keyer == StormAODTInfo.keyerA_v72) { 1607 /* set warmest pixel temperature */ 1608 odtcurrent.warmt = eyet; 1609 /* calculate warmest pixel location */ 1610 float[] out2 = aodtv72_distance2(cursorlat, cursorlon, eye.dist, 1611 eye.angle); 1612 1613 odtcurrent.warmlatitude = out2[0]; // warmlat; 1614 odtcurrent.warmlongitude = out2[1]; // warmlon; 1615 /* store forecast location temperature in eyet */ 1616 odtcurrent.eyet = cursortemp - 273.16f; 1617 // free(tcircfirst_v72); 1618 } else { 1619 /* set eye temperature */ 1620 odtcurrent.eyet = eyet; 1621 /* set cloud temperature and ring distance */ 1622 float[] out3 = aodtv72_calccloudtemp(tcircfirst); 1623 cloudt = out3[0]; 1624 idist = (int) out3[1]; 1625 if ((eyet < -100.0) || (eyet > 40.0)) { 1626 iret = -51; 1627 } 1628 odtcurrent.cwcloudt = cloudt; 1629 odtcurrent.cwring = idist; 1630 } 1631 1632 return odtcurrent; 1633 } 1634 1635 /** 1636 * _more_ 1637 * 1638 * @param keyer 1639 * _more_ 1640 * @param cursortemp 1641 * _more_ 1642 * @param tcircfirst 1643 * _more_ 1644 * 1645 * @return _more_ 1646 */ 1647 static public StormAODTInfo.RingData aodtv72_calceyetemp(int keyer, 1648 float cursortemp, List<StormAODTInfo.RingData> tcircfirst) 1649 /* 1650 * Determine eye/warmest temperature by examining the satellite data between 1651 * 0 and 24/75 km from the storm center location. Eye temperature will be 1652 * warmest temperature found. Inputs : keyer - analysis region radius 1653 * cursortemp - temperature of pixel at cursor location Outputs : eyeangle - 1654 * angle to warmest temperature in eye region (if found) eyedist - distance 1655 * to warmest temperature in eye region (if found) Return : return value is 1656 * warmest eye temperature 1657 */ 1658 { 1659 1660 List<StormAODTInfo.RingData> tcirc; 1661 StormAODTInfo.RingData eye = null; 1662 /* set eye temp to cursor location temperature */ 1663 eye.temp = cursortemp; 1664 1665 eye.dist = 0.0f; 1666 eye.angle = 0.0f; 1667 tcirc = tcircfirst; 1668 Iterator it = tcirc.iterator(); 1669 while (it.hasNext()) { 1670 StormAODTInfo.RingData rd = (StormAODTInfo.RingData) it.next(); 1671 if (rd.dist <= (float) keyer) { 1672 if (rd.temp > eye.temp) { 1673 eye.temp = rd.temp; 1674 eye.dist = rd.dist; 1675 eye.angle = rd.angle; 1676 } 1677 } 1678 1679 } 1680 1681 /* convert temperature to C from K */ 1682 eye.temp = (eye.temp - 273.16f); 1683 1684 return eye; 1685 } 1686 1687 /** 1688 * _more_ 1689 * 1690 * @param tcircfirst 1691 * _more_ 1692 * 1693 * @return _more_ 1694 */ 1695 static public float[] aodtv72_calccloudtemp( 1696 List<StormAODTInfo.RingData> tcircfirst) 1697 /* 1698 * Determine surrounding cloud top region temperature by examining the 1699 * satellite data between kstart_v72(24 km) and kend_v72 (136 km) from the 1700 * storm center location. Cloud temperature will be the coldest value of an 1701 * array of warmest ring temperatures (4 km ring sizes for 4 km infrared 1702 * data). This is the "coldest-warmest" pixel. Inputs : none Outputs : 1703 * irdist - distance (km) from center to cloud top temperature value 1704 * (distance to ring) return value is cloud top temperature value 1705 */ 1706 { 1707 int iyy, b; 1708 int numrings = (StormAODTInfo.kend_v72 - StormAODTInfo.kstart_v72) 1709 / StormAODTInfo.kres_v72; 1710 int kring; 1711 /* float maxtemp[200]; */ 1712 float[] maxtemp; 1713 1714 List<StormAODTInfo.RingData> tcirc; 1715 1716 float cloudtemp = 10000.0f; 1717 1718 float[] out = new float[2]; 1719 int irdist = 0; 1720 /* initialize maxtemp array */ 1721 maxtemp = new float[numrings]; 1722 1723 tcirc = tcircfirst; 1724 Iterator it = tcirc.iterator(); 1725 while (it.hasNext()) { 1726 StormAODTInfo.RingData rd = (StormAODTInfo.RingData) it.next(); 1727 if ((rd.dist >= (float) StormAODTInfo.kstart_v72) 1728 && (rd.dist < (float) StormAODTInfo.kend_v72)) { 1729 kring = ((int) rd.dist - StormAODTInfo.kstart_v72) 1730 / StormAODTInfo.kres_v72; 1731 if (rd.temp > maxtemp[kring]) { 1732 maxtemp[kring] = rd.temp; 1733 } 1734 } 1735 } 1736 1737 /* search maxtemp array for coldest temperature */ 1738 for (iyy = 0; iyy < numrings; iyy++) { 1739 if ((maxtemp[iyy] < cloudtemp) && (maxtemp[iyy] > 160.0)) { 1740 cloudtemp = maxtemp[iyy]; 1741 irdist = (iyy * StormAODTInfo.kres_v72) 1742 + StormAODTInfo.kstart_v72; 1743 } 1744 } 1745 1746 cloudtemp = (cloudtemp - 273.16f); 1747 out[0] = cloudtemp; 1748 out[1] = irdist; 1749 return out; 1750 } 1751 1752 /** 1753 * _more_ 1754 * 1755 * @param ixc 1756 * _more_ 1757 * @param iyc 1758 * _more_ 1759 * @param areadata 1760 * _more_ 1761 * 1762 * @return _more_ 1763 */ 1764 static public List<StormAODTInfo.RingData> aodtv72_readcirc(int ixc, 1765 int iyc, StormAODTInfo.DataGrid areadata) 1766 /* 1767 * Read array of satellite data temperatures and load array containing 1768 * temperatures and lat/lon positions. Inputs : ixc - element location of 1769 * center point iyc - line location of center point Outputs : global 1770 * structure tcirc containing temperature/locations 1771 */ 1772 { 1773 int ixx, iyy, b, count = 0; 1774 float xclat, xclon, xlat, xlon, xdist, xangle; 1775 StormAODTInfo sinfo = new StormAODTInfo(); 1776 StormAODTInfo.RingData tcirc = null; 1777 1778 List<StormAODTInfo.RingData> tcircfirst = new ArrayList(); 1779 1780 /* obtain center/cursor x,y position */ 1781 xclat = areadata.lat[iyc][ixc]; 1782 xclon = areadata.lon[iyc][ixc]; 1783 /* load tcirc array with distance, angle, and temp info */ 1784 1785 for (iyy = 0; iyy < areadata.numy; iyy++) { 1786 for (ixx = 0; ixx < areadata.numx; ixx++) { 1787 xlat = areadata.lat[iyy][ixx]; 1788 xlon = areadata.lon[iyy][ixx]; 1789 float[] outDA = aodtv72_distance(xlat, xlon, xclat, xclon, 1); 1790 xdist = outDA[0]; 1791 xangle = outDA[1]; 1792 if (xdist <= (float) (StormAODTInfo.kend_v72 + 80)) { /* 1793 * add 80.0 1794 * to allow 1795 * for 1796 * correct 1797 * calculation 1798 * of 1799 * annulus 1800 * temp 1801 */ 1802 count++; 1803 tcirc = sinfo.new RingData(xdist, xangle, 1804 areadata.temp[iyy][ixx]); 1805 tcircfirst.add(tcirc); 1806 // tcirc.nextrec=NULL; /* make pointer for last record equal 1807 // to 0 */ 1808 } 1809 } 1810 } 1811 1812 return tcircfirst; 1813 } 1814 1815 /** 1816 * _more_ 1817 * 1818 * @param rrlat 1819 * _more_ 1820 * @param rrlon 1821 * _more_ 1822 * @param pplat 1823 * _more_ 1824 * @param pplon 1825 * _more_ 1826 * @param iunit 1827 * _more_ 1828 * 1829 * @return _more_ 1830 */ 1831 static float[] aodtv72_distance(float rrlat, float rrlon, float pplat, 1832 float pplon, int iunit) 1833 /* 1834 * Calculate distance and angle between two points (rrlat,rrlon and 1835 * pplat,pplon). Inputs : rrlat - latitude of starting point rrlon - 1836 * longitude of starting point rrlat - latitude of ending point rrlon - 1837 * longitude of ending point iunit - flag for output unit type 1838 * (1-km,2-mi,3-nmi) Outputs : dist - distance between two points ang - 1839 * angle between two points (0=north) 1840 */ 1841 { 1842 float z = 0.017453292f, r = 6371.0f; 1843 float rlat, rlon, plat, plon; 1844 float crlat, crlon, srlat, srlon; 1845 float cplat, cplon, splat, splon; 1846 float aa, xx, yy, zz, idist, xdist, xang; 1847 float[] out = new float[2]; 1848 float dist; 1849 float ang; 1850 1851 idist = 0.0f; 1852 rlat = rrlat * z; 1853 rlon = rrlon * z; 1854 plat = pplat * z; 1855 plon = pplon * z; 1856 crlat = (float) Math.cos(rlat); 1857 crlon = (float) Math.cos(rlon); 1858 srlat = (float) Math.sin(rlat); 1859 srlon = (float) Math.sin(rlon); 1860 cplat = (float) Math.cos(plat); 1861 cplon = (float) Math.cos(plon); 1862 splat = (float) Math.sin(plat); 1863 splon = (float) Math.sin(plon); 1864 xx = (cplat * cplon) - (crlat * crlon); 1865 yy = (cplat * splon) - (crlat * srlon); 1866 zz = splat - srlat; 1867 aa = (xx * xx) + (yy * yy) + (zz * zz); 1868 idist = (float) Math.sqrt(aa); 1869 /* xdist is distance in kilometers */ 1870 xdist = 2.0f * (float) Math.asin(idist / 2.0f) * r; 1871 1872 if (iunit == 2) { 1873 xdist = ((69.0f * xdist) + 55f) / 111.0f; /* conversion to miles */ 1874 } 1875 if (iunit == 3) { 1876 xdist = ((60.0f * xdist) + 55f) / 111.0f; /* 1877 * conversion to nautical 1878 * miles 1879 */ 1880 } 1881 dist = xdist; 1882 1883 xang = 0.0f; 1884 if (Math.abs(xdist) > 0.0001) { 1885 xang = (float) ((Math.sin(rlon - plon) * Math.sin((3.14159 / 2.0) 1886 - plat)) / Math.sin(idist)); 1887 } 1888 if (Math.abs(xang) > 1.0) { 1889 xang = (xang >= 0) ? 1 : -1; 1890 } 1891 xang = (float) Math.asin(xang) / z; 1892 if (plat < rlat) { 1893 xang = 180.0f - xang; 1894 } 1895 if (xang < 0.0) { 1896 xang = 360.0f + xang; 1897 } 1898 ang = xang; 1899 out[0] = dist; 1900 out[1] = ang; 1901 1902 return out; 1903 } 1904 1905 /** 1906 * _more_ 1907 * 1908 * @param rlat 1909 * _more_ 1910 * @param rlon 1911 * _more_ 1912 * @param xdist 1913 * _more_ 1914 * @param xang 1915 * _more_ 1916 * 1917 * @return _more_ 1918 */ 1919 static float[] aodtv72_distance2(float rlat, float rlon, float xdist, 1920 float xang) 1921 /* 1922 * Calculate a latitude and longitude position from an initial 1923 * latitude/longitude and distance/angle values. Inputs : rlat - initial 1924 * latitude rlon - initial longitude dist - distance from initial position 1925 * ang - angle from initial position Outputs : plat - derived latitude plon 1926 * - derived longitude 1927 */ 1928 { 1929 float z = 0.017453292f, z90 = 1.570797f; 1930 float clat, clon, cltv, cdis, cang; 1931 float qlat, qlon, argu, tv; 1932 int iang; 1933 float plat, plon; 1934 float[] out = new float[2]; 1935 1936 clat = (90.0f - rlat) * z; 1937 cltv = clat; 1938 clon = rlon * z; 1939 if (rlat < 0.0) { 1940 cltv = -(90.0f + rlat) * z; 1941 clon = (rlon - 180.0f) * z; 1942 xang = 360 - xang; 1943 } 1944 iang = (int) xang; 1945 cang = -(float) (((540 - iang) % 360) * z); 1946 cdis = (xdist / 111.1f) * z; 1947 qlat = (float) Math.acos((Math.cos(clat) * Math.cos(cdis)) 1948 + (Math.sin(clat) * Math.sin(cdis) * Math.cos(cang))); 1949 if (Math.abs(qlat) < 0.0000001) { 1950 qlon = 0.0f; 1951 } else { 1952 argu = (float) (Math.sin(cdis) * Math.sin(cang)) 1953 / (float) Math.sin(qlat); 1954 if (Math.abs(argu) > 1.0) { 1955 argu = (argu >= 0) ? 1 : -1; 1956 ; 1957 } 1958 qlon = (float) Math.asin(argu); 1959 tv = (float) Math.atan(Math.sin(z90 - cang)) 1960 / (float) Math.tan(z90 - cdis); 1961 if (tv > cltv) { 1962 qlon = (2.0f * z90) - qlon; 1963 } 1964 } 1965 qlon = clon - qlon; 1966 plat = 90.0f - (qlat / z); 1967 plon = (float) ((int) (10000 * (qlon / z)) % 3600000) / 10000.0f; 1968 if (plon < -180) { 1969 plon = plon + 360; 1970 } 1971 1972 out[0] = plat; 1973 out[1] = plon; 1974 1975 return out; 1976 } 1977 1978 /** 1979 * _more_ 1980 * 1981 * @param date 1982 * _more_ 1983 * @param time 1984 * _more_ 1985 * 1986 * @return _more_ 1987 */ 1988 static double aodtv72_calctime(int date, int time) 1989 /* 1990 * Compute time in xxxxx.yyy units, where xxxxx is the day and yyy is the 1991 * percentage of the day. This routine will also correct for Y2K problems. 1992 * Inputs : date - Julian date time - time in HHMMSS format Outputs : 1993 * function return value 1994 */ 1995 { 1996 int iyy; 1997 float sec, min, hour, partday; 1998 double timeout; 1999 2000 if ((date % 1000) == 0) { 2001 return 0; 2002 } 2003 if (time < 0) { 2004 return 0; 2005 } 2006 2007 iyy = date / 1000; /* obtain year */ 2008 /* 2009 * check for millenium designation in the year. if it is not there, add 2010 * it onto the beginning 2011 */ 2012 if (iyy < 1900) { 2013 if (iyy > 70) { 2014 date = 1900000 + date; 2015 } else { 2016 date = 2000000 + date; 2017 } 2018 } 2019 2020 sec = ((float) (time % 100)) / 3600.0f; 2021 min = ((float) ((time / 100) % 100)) / 60.0f; 2022 hour = (float) (time / 10000); 2023 partday = (hour + min + sec) / 24.0f; 2024 timeout = (double) date + (double) partday; 2025 2026 return timeout; 2027 } 2028 2029 /** 2030 * 2031 * @param xlat 2032 * @param xlon 2033 * @param tempval 2034 * @param atype 2035 * @param areadata 2036 * _more_ 2037 * @return 2038 */ 2039 static float[] aodtv72_cdoshearcalc(float xlat, float xlon, float tempval, 2040 int atype, StormAODTInfo.DataGrid areadata) 2041 /* 2042 * Determine eye size or shear distance for a given scene. Inputs : xlat - 2043 * center latitude of analysis grid xlon - center longitude of analysis grid 2044 * tempval - temperature threshold value to be used atype - analysis type 2045 * (1-cdo size,2-eye size,3-shear distance) Outputs : valb - eye/cdo radius 2046 * or shear distance valc - eye/cdo symmetry value or 0 2047 */ 2048 { 2049 2050 int ixx, iyy, np, b, numvalid = 0; 2051 float smalldist, vc, maxdist; 2052 float[] zlat, zlon; 2053 float a1, a2, a3, a4, v1, v2, v3; 2054 float valb = 0.f, valc = 0.f; 2055 /* allocate memory */ 2056 2057 np = 0; 2058 int nn = areadata.numx * areadata.numy; 2059 zlat = new float[nn]; 2060 zlon = new float[nn]; 2061 /* CDO size determination - RETURNS RADIUS */ 2062 if (atype == 1) { 2063 /* a1=999.9;a2=999.9;a3=999.9;a4=999.9; */ 2064 a1 = 300.0f; 2065 a2 = 300.0f; 2066 a3 = 300.0f; 2067 a4 = 300.0f; 2068 for (ixx = 0; ixx < areadata.numx; ixx++) { 2069 for (iyy = 0; iyy < areadata.numy; iyy++) { 2070 if (areadata.temp[iyy][ixx] > tempval) { 2071 zlat[np] = areadata.lat[iyy][ixx]; 2072 zlon[np] = areadata.lon[iyy][ixx]; 2073 np++; 2074 } 2075 } 2076 } 2077 /* 2078 * printf("np=%d numx*numy=%d\n",np,areadata_v72->numx*areadata_v72- 2079 * >numy); 2080 */ 2081 maxdist = 0.0f; 2082 if (np < (areadata.numx * areadata.numy)) { 2083 for (ixx = 0; ixx < np; ixx++) { 2084 float[] out = aodtv72_distance(xlat, xlon, zlat[ixx], 2085 zlon[ixx], 1); 2086 if (out[0] > maxdist) { 2087 maxdist = out[0]; 2088 } 2089 /* determine size of CDO */ 2090 if (out[0] > StormAODTInfo.keyerM_v72) { 2091 if ((Math.abs(out[1] - 45.0) <= 15.0) && (out[0] < a1)) { 2092 a1 = out[0]; 2093 } 2094 if ((Math.abs(out[1] - 135.0) <= 15.0) && (out[0] < a2)) { 2095 a2 = out[0]; 2096 } 2097 if ((Math.abs(out[1] - 225.0) <= 15.0) && (out[0] < a3)) { 2098 a3 = out[0]; 2099 } 2100 if ((Math.abs(out[1] - 315.0) <= 15.0) && (out[0] < a4)) { 2101 a4 = out[0]; 2102 } 2103 } 2104 } 2105 /* printf("a1=%f a2=%f a3=%f a4=%f\n",a1,a2,a3,a4); */ 2106 numvalid = 4; 2107 v3 = StormAODTInfo.keyerM_v72 + StormAODTInfo.kres_v72; 2108 if (a1 < v3) { 2109 numvalid--; 2110 } 2111 if (a2 < v3) { 2112 numvalid--; 2113 } 2114 if (a3 < v3) { 2115 numvalid--; 2116 } 2117 if (a4 < v3) { 2118 numvalid--; 2119 } 2120 } else { 2121 a1 = 0.0f; 2122 a2 = 0.0f; 2123 a3 = 0.0f; 2124 a4 = 0.0f; 2125 } 2126 if (numvalid < 3) { 2127 valb = 0.0f; 2128 valc = 0.0f; 2129 } else { 2130 a1 = Math.min(a1, maxdist); 2131 a2 = Math.min(a2, maxdist); 2132 a3 = Math.min(a3, maxdist); 2133 a4 = Math.min(a4, maxdist); 2134 valb = (a1 + a2 + a3 + a4) / 4.0f; 2135 /* *valc=A_ABS(((a1+a3)/2.0)-((a2+a4)/2.0))/2.0; */ 2136 v1 = a1 + a3; 2137 v2 = a2 + a4; 2138 vc = v1 / v2; 2139 vc = Math.max(vc, 1.0f / vc); 2140 valc = vc; 2141 } 2142 /* 2143 * printf("\nnp=%5.5d a1=%5.1f a2=%5.1f a3=%5.1f a4=%5.1f ",np,a1,a2 2144 * ,a3,a4); 2145 */ 2146 } 2147 2148 /* shear distance determination */ 2149 if (atype == 3) { 2150 a1 = 999.9f; 2151 a2 = 999.9f; 2152 a3 = 999.9f; 2153 a4 = 999.9f; 2154 for (ixx = 0; ixx < areadata.numx; ixx++) { 2155 for (iyy = 0; iyy < areadata.numy; iyy++) { 2156 if (areadata.temp[iyy][ixx] <= tempval) { 2157 zlat[np] = areadata.lat[iyy][ixx]; 2158 zlon[np] = areadata.lon[iyy][ixx]; 2159 np++; 2160 } 2161 } 2162 } 2163 smalldist = 999.9f; 2164 for (ixx = 0; ixx < np; ixx++) { 2165 float[] out = aodtv72_distance(xlat, xlon, zlat[ixx], 2166 zlon[ixx], 1); 2167 if (out[0] < smalldist) { 2168 smalldist = out[0]; 2169 } 2170 } 2171 valb = smalldist; 2172 valc = 0.0f; 2173 2174 } 2175 2176 /* free memory */ 2177 2178 float[] out = { valb, valc }; 2179 return out; 2180 2181 } 2182 2183 }