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    }