001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2017 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.adt; 030 031public class Output { 032 033 static String[] Months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; 034 035 /** N/S hemisphere character value */ 036 static String[] LatNS = {"N","S"}; 037 038 /** E/W hemisphere character value */ 039 static String[] LonWE = {"W","E"}; 040 041 /** Rule 9 string array */ 042 static String[] Rule9String = { "OFF ","ON ","WEAKEN" }; 043 044 /** rapid dissipation string array */ 045 static String[] RapidString = { "OFF ","FLAG ","ON ","ON " }; 046 047 /** BD curve value string array */ 048 static String[] BDCatString = { "LOW CLD","OFF WHT","DK GRAY","MD GRAY", "LT GRAY","BLACK ","WHITE " }; 049 050 /** ocean basin string array */ 051 static String[] BasinString = { "ATLANTIC ","WEST PACIFIC", "EAST PACIFIC","INDIAN " }; 052 053 /** eye scene type array */ 054 static String[] EyeSceneTypes = { "EYE","PINHOLE EYE","LARGE EYE","NONE" }; 055 056 /** cloud scene type array */ 057 static String[] CloudSceneTypes = { "UNIFORM CDO","EMBEDDED CENTER","IRREGULAR CDO","CURVED BAND","SHEAR","EYE" }; 058 059 /** storm position type arrays */ 060 static String[] AutoPosString = { "MANUAL", "FORECAST INTERPOLATION", "LAPLACIAN ANALYSIS", "WARMEST PIXEL SEARCH", 061 "SPIRAL ANALYSIS", "RING/SPIRAL COMBINATION", "LINEAR EXTRAPOLATION", 062 "NETCDF NOMINAL POSITION", "NOT AVAILABLE"}; 063 064 static String[] AutoPosStringAbbr = { " MAN ","FCST ", "LAPL ", "WARM ", "SPRL ", "COMBO", "EXTRP", "NETCDF", " N/A " }; 065 066 /** basin ID string array */ 067 static String[] PW_BasinValues = { "ATLANTIC","PACIFIC " }; 068 069 /** Rule 8 string array */ 070 static String[] Rule8String = { "NO LIMIT ","0.5T/6hr ","1.0T/6hr ","1.7T/12hr", 071 "2.2T/18hr","2.7T/24hr"," "," ", 072 "0.2T/hour","0.5T/hour", 073 "NO LIMIT ","0.5T/6hr ","1.0T/6hr ","2.7T/12hr", 074 "3.2T/18hr","3.7T/24hr"," "," ", 075 "0.2T/hour","0.5T/hour", 076 "NO LIMIT ","0.5T/6hr ","0.7T/6hr ","1.2T/12hr", 077 "1.7T/18hr","2.2T/24hr"," "," ", 078 "0.2T/hour","0.5T/hour", 079 "MW Adjst ","MW ON ","MW ON ","MW HOLD ", 080 "MW AdjEnd" }; 081 082 public Output() { 083 } 084 085 public static String TextScreenOutput(String HistoryFileName){ 086 087 System.err.println("TextScreenOutput() in..."); 088 String TextScreen_Return = ""; 089 090 /* int LatNSval = 0; */ 091 /* int LonWEval = 0; */ 092 String SceneString = ""; 093 String RadiusMaxWindString = ""; 094 String SceneMaxCBString = ""; 095 String SceneMaxCBLLString = ""; 096 String SceneMaxCBString2 = ""; 097 String SceneMaxCBLLString2 = ""; 098 double PresWindValue_Pressure = -999.0; 099 double PresWindValue_Wind = -999.0; 100 boolean MaxCurvedBandTF = false; 101 boolean RadiusMaxWindTF = false; 102 103 /* convert Julian date/time to DateValue/month/year format */ 104 int CurDate = History.IRCurrentRecord.date; 105 int CurTime = History.IRCurrentRecord.time; 106 double CurLatitudeValue = History.IRCurrentRecord.latitude; 107 double CurLongitudeValue = History.IRCurrentRecord.longitude; 108 int[] ReturnValues = Functions.adt_yddmy(CurDate); 109 int DateValue = ReturnValues[0]; 110 int MonthValue = ReturnValues[1]; 111 int YearValue = ReturnValues[2]; 112 113 /* format character string for date output */ 114 String DateString = String.format("%02d %3s %04d",DateValue,Months[MonthValue-1],YearValue); 115 116 /* format character string for time output */ 117 String TimeString = String.format(" %06d UTC",CurTime); 118 119 /* convert xx.xxxx latitude format to degree/minute/second format */ 120 int[] ReturnValues2A = adt_lldms(CurLatitudeValue); 121 int DegreeValue2A = ReturnValues2A[0]; 122 int MinuteValue2A = ReturnValues2A[1]; 123 int SecondValue2A = ReturnValues2A[2]; 124 int LatNSval = (CurLatitudeValue<0.0) ? 1 : 0; 125 /* 126 LatNSval=0; 127 if(CurLatitudeValue<0.0) { 128 LatNSval=1; 129 } 130 */ 131 /* format character string for latitude output */ 132 String LatitudeString = String.format("%3d:%02d:%02d %1s",DegreeValue2A,MinuteValue2A,SecondValue2A,LatNS[LatNSval]); 133 134 int[] ReturnValues2B = adt_lldms(CurLongitudeValue); 135 int DegreeValue2B = ReturnValues2B[0]; 136 int MinuteValue2B = ReturnValues2B[1]; 137 int SecondValue2B = ReturnValues2B[2]; 138 /* int LonWEval = (CurLongitudeValue<0.0) ? 1 : 0; old McIDAS-X conversion */ 139 int LonWEval = (CurLongitudeValue<0.0) ? 0 : 1; 140 /* 141 LonWEval=0; 142 if(CurLongitudeValue<0.0) { 143 LonWEval=1; 144 } 145 */ 146 /* format character string for latitude output */ 147 String LongitudeString = String.format("%3d:%02d:%02d %1s",DegreeValue2B,MinuteValue2B,SecondValue2B,LonWE[LonWEval]); 148 149 int[] ReturnValues3 = Functions.adt_oceanbasin(CurLatitudeValue,CurLongitudeValue); 150 int BasinIDValue = ReturnValues3[0]; 151 int DomainID = ReturnValues3[1]; 152 153 /* determine Dvorak pressure/wind speed in relation to final CI # */ 154 double CurRawT = History.IRCurrentRecord.Traw; 155 double CurRawTorig = History.IRCurrentRecord.TrawO; 156 double CurFinalT = History.IRCurrentRecord.Tfinal; 157 double CurCI = History.IRCurrentRecord.CI; 158 double CurCIAdjP = History.IRCurrentRecord.CIadjp; 159 /* System.out.printf("ciadjp=%f\n",CurCIAdjP); */ 160 PresWindValue_Pressure = Functions.adt_getpwval(0,CurCI,CurLatitudeValue,CurLongitudeValue); 161 PresWindValue_Wind = Functions.adt_getpwval(1,CurCI,CurLatitudeValue,CurLongitudeValue); 162 163 boolean Vmax1or10TF = Env.Vmax1or10TF; 164 165 if(!Vmax1or10TF) { 166 /* convert 1-minute to 10-minute average Vmax for output */ 167 PresWindValue_Wind=0.88*PresWindValue_Wind; 168 } 169 170 /* determine Rule 8 and Rule 9 screen output values */ 171 int Rule8Value = History.IRCurrentRecord.rule8; 172 int Rule9Value = History.IRCurrentRecord.rule9; 173 int RapidIntenValue = History.IRCurrentRecord.rapiddiss; 174 175 double EyeTempValue = History.IRCurrentRecord.eyet; 176 double CloudTempValue = History.IRCurrentRecord.cloudt; 177 178 /* determine scenetype to be output to screen */ 179 int EyeSceneTypeValue = History.IRCurrentRecord.eyescene; 180 int CloudSceneTypeValue = History.IRCurrentRecord.cloudscene; 181 182 if(CloudSceneTypeValue==2) { 183 SceneString = String.format("%s",CloudSceneTypes[CloudSceneTypeValue]); 184 } else if(CloudSceneTypeValue==3) { 185 double CurvedBandValue = ((double)(History.IRCurrentRecord.ringcbval-1))/24.0; 186 double CurvedBandMaxValue = ((double)(History.IRCurrentRecord.ringcbvalmax-1))/25.0; 187 int RingCB = History.IRCurrentRecord.ringcb; 188 SceneString = String.format("CURVED BAND with %4.2f ARC in %s",CurvedBandValue,BDCatString[RingCB]); 189 /* System.out.printf("curved band max=%f curved band=%f\n",CurvedBandMaxValue,CurvedBandValue); */ 190 if(CurvedBandMaxValue>CurvedBandValue) { 191 MaxCurvedBandTF = true; 192 } 193 if(MaxCurvedBandTF) { 194 SceneMaxCBString = String.format("Maximum CURVED BAND with %4.2f ARC in %s",CurvedBandMaxValue,BDCatString[RingCB]); 195 /* convert xx.xxxx latitude format to degree/minute/second format */ 196 double CurvedBandMaxLatitude = History.IRCurrentRecord.ringcbvalmaxlat; 197 int[] ReturnValues4A = adt_lldms(CurvedBandMaxLatitude); 198 int DegreeValue4A = ReturnValues4A[0]; 199 int MinuteValue4A = ReturnValues4A[1]; 200 int SecondValue4A = ReturnValues4A[2]; 201 LatNSval = (CurLatitudeValue<0.0) ? 1 : 0; 202 /* 203 LatNSval=0; 204 if(CurvedBandMaxLatitude<0.0) { 205 LatNSval=1; 206 } 207 */ 208 /* format character string for latitude output */ 209 String CBMaxLatString = String.format("%3d:%02d:%02d %1s",DegreeValue4A,MinuteValue4A,SecondValue4A,LatNS[LatNSval]); 210 211 /* convert xx.xxxx longitude format to degree/minute/second format */ 212 double CurvedBandMaxLongitude = History.IRCurrentRecord.ringcbvalmaxlon; 213 int[] ReturnValues4B = adt_lldms(CurvedBandMaxLongitude); 214 int DegreeValue4B = ReturnValues4B[0]; 215 int MinuteValue4B = ReturnValues4B[1]; 216 int SecondValue4B = ReturnValues4B[2]; 217 /* LonWEval = (CurLongitudeValue<0.0) ? 1 : 0; old conversion for McIDAS-X */ 218 LonWEval = (CurLongitudeValue<0.0) ? 0 : 1; 219 /* 220 LonWEval=0; 221 if(CurvedBandMaxLongitude<0.0) { 222 LonWEval=1; 223 } 224 */ 225 /* format character string for longitude output */ 226 String CBMaxLonString = String.format("%3d:%02d:%02d %1s",DegreeValue4B,MinuteValue4B,SecondValue4B,LonWE[LonWEval]); 227 SceneMaxCBLLString = String.format(" at Lat:%12s Lon:%12s",CBMaxLatString,CBMaxLonString); 228 } 229 } 230 else if(CloudSceneTypeValue==4) { 231 double CDOSizeValue = History.IRCurrentRecord.eyecdosize/110.0; 232 if(CDOSizeValue<1.30) { 233 SceneString = String.format("SHEAR (%4.2f^ TO DG)",CDOSizeValue); 234 } else { 235 SceneString = String.format("SHEAR (>1.25^ TO DG)"); 236 } 237 } 238 else { 239 if(EyeSceneTypeValue<=2) { 240 SceneString = String.format("%s ",EyeSceneTypes[EyeSceneTypeValue]); 241 if(EyeSceneTypeValue<=2) { 242 RadiusMaxWindTF = true; 243 } 244 double RMWValue = History.IRCurrentRecord.rmw; 245 if(RMWValue<0.0) { 246 if(EyeSceneTypeValue==1) { 247 RadiusMaxWindString = String.format("<10"); 248 249 } else { 250 RadiusMaxWindString = String.format("N/A"); 251 } 252 } else { 253 RadiusMaxWindString = String.format("%3d",(int)RMWValue); 254 } 255 } 256 else { 257 if((Rule8Value==31)||(Rule8Value==32)) { 258 SceneString = String.format("%s CLOUD REGION w/ MW EYE",CloudSceneTypes[CloudSceneTypeValue]); 259 } else { 260 SceneString = String.format("%s CLOUD REGION",CloudSceneTypes[CloudSceneTypeValue]); 261 } 262 } 263 } 264 265 int NumRecsHistory = History.HistoryNumberOfRecords(); 266 double InitStrengthValue = Env.InitRawTValue; 267 if((HistoryFileName!=null)&&(NumRecsHistory==0)) { 268 CloudSceneTypeValue=0; 269 if(InitStrengthValue>1.0) { 270 SceneString = String.format("USER DEFINED INITIAL CLASSIFICATION"); 271 } else { 272 if(InitStrengthValue==1.0) { 273 SceneString = String.format("INITIAL CLASSIFICATION"); 274 } 275 } 276 } 277 if(InitStrengthValue<0.0) { 278 SceneString = String.format("USER REINITIALIZED CLASSIFICATION"); 279 } 280 String SceneString2 = String.format("%s",SceneString); 281 if(MaxCurvedBandTF) { 282 SceneMaxCBString2 = String.format("%s",SceneMaxCBString); 283 SceneMaxCBLLString2 = String.format("%s",SceneMaxCBLLString); 284 } 285 286 int SatType = History.IRCurrentRecord.sattype; 287 int AutoPos = History.IRCurrentRecord.autopos; 288 int LandFlag = History.IRCurrentRecord.land; 289 int R34Value = History.IRCurrentRecord.r34; 290 int MSLPenvValue = History.IRCurrentRecord.MSLPenv; 291 double VZAValue = History.IRCurrentRecord.vza; 292 String SatelliteIDString = Functions.adt_sattypes(SatType); 293 294 String VersionString = Env.ADTVersion; 295 boolean LandFlagTF = Env.LandFlagTF; 296 boolean UseCKZTF = Env.UseCKZTF; 297 298 /* send results to the screen */ 299 300 TextScreen_Return += String.format("\n****************************************************\n\n"); 301 TextScreen_Return += String.format(" UW - CIMSS \n"); 302 TextScreen_Return += String.format(" ADVANCED DVORAK TECHNIQUE \n"); 303 TextScreen_Return += String.format(" %17s \n",VersionString); 304 TextScreen_Return += String.format(" Tropical Cyclone Intensity Algorithm \n\n"); 305 TextScreen_Return += String.format(" ----- Current Analysis ----- \n"); 306 TextScreen_Return += String.format(" Date : %12s Time : %12s\n",DateString,TimeString); 307 TextScreen_Return += String.format(" Lat : %12s Lon : %12s\n\n",LatitudeString, 308 LongitudeString); 309 if((LandFlagTF)&&(LandFlag==1)) { 310 TextScreen_Return += String.format(" TROPICAL CYCLONE OVER LAND\n"); 311 TextScreen_Return += String.format(" NO ADT ANALYSIS AVAILABLE\n"); 312 } 313 else { 314 if(Vmax1or10TF) { 315 TextScreen_Return += String.format(" CI# /Pressure/ Vmax\n"); 316 } else { 317 TextScreen_Return += String.format(" CI# /Pressure/ Vmax(10-min)\n"); 318 } 319 if(UseCKZTF) { 320 TextScreen_Return += String.format(" %3.1f /%6.1fmb/%5.1fkt\n\n",CurCI, 321 PresWindValue_Pressure,PresWindValue_Wind); 322 } else { 323 TextScreen_Return += String.format(" %3.1f /%6.1fmb/%5.1fkt\n\n",CurCI, 324 PresWindValue_Pressure+CurCIAdjP, PresWindValue_Wind); 325 } 326 if(HistoryFileName!=null) { 327 TextScreen_Return += String.format(" Final T# Adj T# Raw T# \n"); 328 TextScreen_Return += String.format(" %3.1f %3.1f %3.1f\n\n",CurFinalT,CurRawT,CurRawTorig); 329 } 330 if(!UseCKZTF) { 331 TextScreen_Return += String.format(" Latitude bias adjustment to MSLP : %+5.1fmb\n\n",CurCIAdjP); 332 } 333 if(RadiusMaxWindTF) { 334 TextScreen_Return += String.format(" Estimated radius of max. wind based on IR :%3s km\n\n",RadiusMaxWindString); 335 } 336 TextScreen_Return += String.format(" Center Temp : %+5.1fC Cloud Region Temp : %5.1fC\n",EyeTempValue,CloudTempValue); 337 TextScreen_Return += String.format("\n Scene Type : %s \n",SceneString2); 338 if(MaxCurvedBandTF) { 339 TextScreen_Return += String.format(" %s \n",SceneMaxCBString2); 340 TextScreen_Return += String.format(" %s \n",SceneMaxCBLLString2); 341 } 342 TextScreen_Return += String.format("\n Positioning Method : %s \n",AutoPosString[AutoPos]); 343 TextScreen_Return += String.format("\n Ocean Basin : %12s \n",BasinString[BasinIDValue]); 344 TextScreen_Return += String.format(" Dvorak CI > MSLP Conversion Used : %8s \n",PW_BasinValues[DomainID]); 345 if(HistoryFileName!=null) { 346 TextScreen_Return += String.format("\n Tno/CI Rules : Constraint Limits : %9s\n", Rule8String[Rule8Value]); 347 TextScreen_Return += String.format(" Weakening Flag : %6s\n", Rule9String[Rule9Value]); 348 TextScreen_Return += String.format(" Rapid Dissipation Flag : %6s\n", RapidString[RapidIntenValue]); 349 } 350 if(UseCKZTF) { 351 TextScreen_Return += String.format("\n C/K/Z MSLP Estimate Inputs :\n"); 352 if(R34Value>0.0) { 353 TextScreen_Return += String.format(" - Average 34 knot radii : %4dkm\n",R34Value); 354 } else { 355 TextScreen_Return += String.format(" - Average 34 knot radii : N/A\n"); 356 } 357 TextScreen_Return += String.format(" - Environmental MSLP : %4dmb\n",MSLPenvValue); 358 } 359 TextScreen_Return += String.format("\n Satellite Name : %7s \n",SatelliteIDString); 360 TextScreen_Return += String.format(" Satellite Viewing Angle : %4.1f degrees \n",VZAValue); 361 } 362 TextScreen_Return += String.format("\n****************************************************\n\n"); 363 364 System.err.println("TextScreenOutput() out, val: " + TextScreen_Return); 365 return TextScreen_Return; 366 } 367 368 /** 369 * Convert "degree.partial_degree" to degree/minute/second format. 370 * 371 * @param FullDegreeValue Latitude/Longitude value to convert. 372 * 373 * @return Array whose values represent (in order): degrees, minutes, and 374 * seconds. 375 */ 376 public static int[] adt_lldms(double FullDegreeValue) { 377 int DegreeValue = (int)FullDegreeValue; 378 double MinuteValue = (FullDegreeValue-(double)DegreeValue)*60.0; 379 double SecondValue = (MinuteValue-(double)((int)MinuteValue))*60.0; 380 int DegreeReturn = Math.abs(DegreeValue); 381 int MinuteReturn = (int)Math.abs(MinuteValue); 382 int SecondReturn = (int)Math.abs(SecondValue); 383 384 return new int[] { DegreeReturn, MinuteReturn, SecondReturn }; 385 } 386}