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.data.cyclone;
030
031 import java.text.DecimalFormat;
032 import java.util.Calendar;
033 import java.util.GregorianCalendar;
034
035 import ucar.unidata.util.DateUtil;
036 import ucar.unidata.util.HtmlUtil;
037 import visad.DateTime;
038 import 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
045 public 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 }