001/*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2023
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}