001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2016 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 029package edu.wisc.ssec.mcidasv.data.cyclone; 030 031import java.text.DecimalFormat; 032import java.util.Calendar; 033import java.util.GregorianCalendar; 034 035import ucar.unidata.util.DateUtil; 036import ucar.unidata.util.HtmlUtil; 037import visad.DateTime; 038import visad.VisADException; 039 040/** 041 * Created by IntelliJ IDEA. User: yuanho Date: Mar 9, 2009 Time: 2:16:30 PM To 042 * change this template use File | Settings | File Templates. 043 */ 044 045public class StormAODTUtil { 046 047 /** 048 * _more_ 049 * 050 * @param odtcurrent 051 * _more_ 052 * @param latLonFormat 053 * _more_ 054 * 055 * @return _more_ 056 */ 057 public static String aodtv72_textscreenoutput( 058 StormAODTInfo.IRData odtcurrent, DecimalFormat latLonFormat) 059 /* 060 * Output information to text screen. Inputs : global structure 061 * odtcurrent_v72 containting current image information Outputs : none 062 */ 063 { 064 065 int domain = odtcurrent.domain; 066 int day, mon, year, ibasin, iok; 067 int degree, minute, second, xr8 = 0, xr9 = 0, xrpd = 0; 068 int cloudcat, eyecat, cfft; 069 int ptr, ptr2, nptr; 070 String cdate, ctime, clat, clon; 071 String cmin, csec, clatmax, clonmax; 072 char iout2; 073 String latc = "N", lonc = "W"; 074 String[] cr9 = { "OFF ", "ON ", "WEAKEN" }; 075 String[] crpd = { "OFF ", "FLAG ", "ON ", "ON " }; 076 String[] cbd = { "LOW CLD", "OFF WHT", "DK GRAY", "MD GRAY", "LT GRAY", 077 "BLACK ", "WHITE " }; 078 String[] cr8 = { "NO LIMIT ", "0.5T/6hr ", "1.2T/6hr ", "1.7T/12hr", 079 "2.2T/18hr", "2.7T/24hr", " ", " ", 080 "0.1T/hour", "0.5T/hour", "NO LIMIT ", "0.5T/6hr ", 081 "1.7T/6hr ", "2.2T/12hr", "2.7T/18hr", "3.2T/24hr", 082 " ", " ", "0.1T/hour", "0.5T/hour", 083 "NO LIMIT ", "0.5T/6hr ", "0.7T/6hr ", "1.2T/12hr", 084 "1.7T/18hr", "2.2T/24hr", " ", " ", 085 "0.1T/hour", "0.5T/hour" }; 086 String[] basin = { "ATLANTIC ", "WEST PACIFIC", "EAST PACIFIC", 087 "INDIAN " }; 088 String[] cuse = { "MANUAL", "FORECAST INTERPOLATION", 089 "LAPLACIAN ANALYSIS", "WARMEST PIXEL SEARCH", 090 "SPIRAL ANALYSIS", "RING/SPIRAL COMBINATION", 091 "LINEAR EXTRAPOLATION" }; 092 String scenetype; 093 String scenetypemax; 094 String scenetypemaxll; 095 String eyermw; 096 String version; 097 float pwip, pwiw, cloudtemp, arcd, arcdmax, sdist, xlat, xlon, m; 098 boolean bettercb = false, rmwflag = false; 099 100 /* convert Julian date/time to day/month/year format */ 101 int[] out = aodtv72_yddmy(odtcurrent.date); 102 103 ctime = ""; 104 try { 105 DateTime ddt = new DateTime(odtcurrent.date); 106 ctime = ddt.toString(); 107 } catch (Exception e) { 108 } 109 110 /* convert xx.xxxx latitude format to degree/minute/second format */ 111 xlat = odtcurrent.latitude; 112 xlon = odtcurrent.longitude; 113 out = aodtv72_lldms(xlat); 114 degree = out[0]; 115 minute = out[1]; 116 second = out[2]; 117 118 if (xlat < 0.0) { 119 latc = "S"; 120 } 121 /* format character string for latitude output */ 122 123 clat = Integer.toString(degree) + "-" + Integer.toString(minute) + "-" 124 + Integer.toString(second) + latc; 125 126 /* convert xx.xxxx longitude format to degree/minute/second format */ 127 out = aodtv72_lldms(xlon); 128 degree = out[0]; 129 minute = out[1]; 130 second = out[2]; 131 if (xlon < 0.0) { 132 lonc = "E"; 133 } 134 /* format character string for longitude output */ 135 136 clon = Integer.toString(degree) + "-" + Integer.toString(minute) + "-" 137 + Integer.toString(second) + lonc; 138 139 /* determine current ocean basin in which storm is located */ 140 // ibasin=aodtv72_oceanbasin(xlat,xlon); 141 142 /* determine Dvorak pressure/wind speed in relation to final CI # */ 143 pwip = aodtv72_getpwval(0, odtcurrent.CI, domain); 144 pwiw = aodtv72_getpwval(1, odtcurrent.CI, domain); 145 146 /* determine Rule 8 and Rule 9 screen output values */ 147 xr8 = odtcurrent.rule8; 148 if (odtcurrent.rule9 == 1) { 149 xr9 = 1; 150 } 151 xrpd = odtcurrent.rapiddiss; 152 cloudtemp = odtcurrent.cloudt; 153 /* determine scenetype to be output to screen */ 154 eyecat = odtcurrent.eyescene; 155 cloudcat = odtcurrent.cloudscene; 156 cfft = odtcurrent.cloudfft; 157 if (cloudcat == 2) { 158 scenetype = StormAODTInfo.cloudtype_v72[cloudcat]; 159 } else if (cloudcat == 3) { 160 arcd = (float) (odtcurrent.ringcbval - 1) / 24.0f; 161 arcdmax = (float) (odtcurrent.ringcbvalmax - 1) / 25.0f; 162 if (arcdmax > arcd) { 163 bettercb = true; 164 } 165 scenetype = "CURVED BAND with " + arcd + " ARC in " 166 + cbd[odtcurrent.ringcb]; 167 168 if (bettercb) { 169 scenetypemax = "Maximum CURVED BAND with " + arcdmax 170 + " ARC in " + cbd[odtcurrent.ringcb]; 171 172 /* 173 * convert xx.xxxx latitude format to degree/minute/second 174 * format 175 */ 176 out = aodtv72_lldms(odtcurrent.ringcblatmax); 177 degree = out[0]; 178 minute = out[1]; 179 second = out[2]; 180 181 if (odtcurrent.ringcblatmax < 0.0) { 182 latc = "S"; 183 } 184 /* format character string for latitude output */ 185 clatmax = Integer.toString(degree) + "-" 186 + Integer.toString(minute) + "-" 187 + Integer.toString(second) + latc; 188 189 /* 190 * convert xx.xxxx longitude format to degree/minute/second 191 * format 192 */ 193 out = aodtv72_lldms(odtcurrent.ringcblonmax); 194 degree = out[0]; 195 minute = out[1]; 196 second = out[2]; 197 198 if (odtcurrent.ringcblonmax < 0.0) { 199 lonc = "E"; 200 } 201 /* format character string for longitude output */ 202 clonmax = Integer.toString(degree) + "-" 203 + Integer.toString(minute) + "-" 204 + Integer.toString(second) + lonc; 205 206 scenetypemaxll = " at Lat:" + clatmax + " Lon:" + clonmax; 207 208 } 209 } else if (cloudcat == 4) { 210 sdist = odtcurrent.eyecdosize / 110.0f; 211 if (sdist < 1.30) { 212 scenetype = "SHEAR (%4.2f^ TO DG)* " + sdist; 213 } else { 214 scenetype = "SHEAR (>1.25^ TO DG)*"; 215 } 216 217 } else { 218 if (eyecat <= 2) { 219 scenetype = StormAODTInfo.eyetype_v72[eyecat]; 220 if (eyecat <= 2) { 221 rmwflag = true; 222 } 223 224 if (odtcurrent.rmw < 0.0) { 225 if (eyecat == 1) { 226 eyermw = "<10"; 227 } else { 228 eyermw = "N/A"; 229 } 230 } else { 231 eyermw = Integer.toString((int) odtcurrent.rmw); 232 /* if(eyecat==1) sprintf(eyermw,"<10"); */ 233 } 234 } else { 235 scenetype = "CLOUD REGION* " 236 + StormAODTInfo.cloudtype_v72[cloudcat]; 237 } 238 239 } 240 241 StringBuffer result = new StringBuffer(); 242 243 /* send results to the screen */ 244 result.append("<table>"); 245 result.append(HtmlUtil.row(label("Time:") + HtmlUtil.col(ctime) 246 + label("Lat:") 247 + HtmlUtil.col(latLonFormat.format(odtcurrent.latitude)) 248 + label("Lon:") 249 + HtmlUtil.col(latLonFormat.format(odtcurrent.longitude)))); 250 result.append("</table>"); 251 result.append("<table>"); 252 result.append(HtmlUtil.row(HtmlUtil.cols("<b>CI#</b>", 253 "<b>Pressure</b>", "<b>Vmax</b>"))); 254 result.append(HtmlUtil.row(HtmlUtil.cols("" + odtcurrent.CI, "" 255 + (pwip + odtcurrent.CIadjp), "" + pwiw))); 256 result.append("</table>"); 257 result.append("<hr>"); 258 result.append("<table>"); 259 result.append(HtmlUtil.row(label("Latitude bias adjustment to MSLP:") 260 + HtmlUtil.col("" + odtcurrent.CIadjp))); 261 262 result.append("</table>"); 263 result.append("<table>"); 264 result.append(HtmlUtil.row(label("Center Temp:") 265 + HtmlUtil.col("" + odtcurrent.eyet))); 266 result.append(HtmlUtil.row(label("Cloud Region Temp:") 267 + HtmlUtil.col("" + cloudtemp))); 268 result.append(HtmlUtil.row(label("Scene Type:") 269 + HtmlUtil.col(scenetype))); 270 result.append("</table>"); 271 return result.toString(); 272 273 } 274 275 private static String label(String label) { 276 return HtmlUtil.colRight(HtmlUtil.b(label)); 277 } 278 279 /** 280 * _more_ 281 * 282 * @param llval 283 * _more_ 284 * 285 * @return _more_ 286 */ 287 public static int[] aodtv72_lldms(float llval) 288 /* 289 * Convert degree.degree to degree/minute/second format. Inputs : llval - 290 * latitude/longitude to convert Outputs : degree - degrees minute - minutes 291 * second - seconds 292 */ 293 { 294 int deg; 295 float min, sec; 296 297 deg = (int) llval; 298 min = (llval - (float) deg) * 60.0f; 299 sec = (min - (float) ((int) min)) * 60.0f; 300 301 int[] out = { deg, (int) min, (int) sec }; 302 303 return out; 304 } 305 306 /** 307 * _more_ 308 * 309 * @param syd 310 * _more_ 311 * 312 * @return _more_ 313 */ 314 public static int[] aodtv72_yddmy(double syd) 315 /* 316 * Convert yyyyddd to dd/mm/yy format. Inputs : syd - Julian day (yyyyddd) 317 * Outputs : day - date month - month year - year (yyyy) 318 */ 319 { 320 DateTime dt = null; 321 GregorianCalendar cal = new GregorianCalendar(DateUtil.TIMEZONE_GMT); 322 try { 323 dt = new DateTime(syd); 324 cal.setTime(ucar.visad.Util.makeDate(dt)); 325 } catch (Exception e) { 326 327 } 328 329 int year = cal.get(Calendar.YEAR); 330 int mon = cal.get(Calendar.MONTH); 331 int day = cal.get(Calendar.DAY_OF_MONTH); 332 int[] out = { day, mon, year }; 333 return out; 334 335 } 336 337 public static int getYear(DateTime dttm) throws VisADException { 338 GregorianCalendar cal = new GregorianCalendar(DateUtil.TIMEZONE_GMT); 339 cal.setTime(ucar.visad.Util.makeDate(dttm)); 340 return cal.get(Calendar.YEAR); 341 } 342 343 /** 344 * _more_ 345 * 346 * @param ival 347 * _more_ 348 * @param cival 349 * _more_ 350 * @param idomain_v72 351 * _more_ 352 * 353 * @return _more_ 354 */ 355 public static float aodtv72_getpwval(int ival, float cival, int idomain_v72) 356 /* 357 * Obtain pressure or wind_v72 value (for Atlantic or West Pacific storms) 358 * given the intensity estimate value. Inputs : ival - flag for wind_v72 (1) 359 * or pressure (0) output cival - Current Intensity (CI) value Outputs : 360 * return value is pressure/wind_v72 value 361 */ 362 { 363 float value; 364 int ixx = 2; 365 366 /* determine correct pressure/wind_v72 array bin */ 367 while ((cival > StormAODTInfo.tno_v72[ixx]) && (ixx < 82)) { 368 ixx++; 369 } 370 371 /* convert CI value to wind_v72/pressure value */ 372 if (ival == 1) { 373 value = (float) StormAODTInfo.wind_v72[ixx]; /* WIND */ 374 } else { 375 value = (float) StormAODTInfo.pres_v72[idomain_v72][ixx]; /* PRESSURE */ 376 } 377 378 return value; 379 } 380 381}