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    }