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