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 031import java.io.BufferedWriter; 032import java.io.File; 033import java.io.FileWriter; 034import java.io.IOException; 035import java.util.Scanner; 036 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040class IRHistoryRecord { 041 int date; 042 int time; 043 double TrawO; 044 double Traw; 045 double Tfinal; 046 double CI; 047 double eyet; 048 double cloudt; 049 double cloudt2; 050 double cwcloudt; 051 double latitude; 052 double longitude; 053 double eyecdosize; 054 double eyestdv; 055 double cloudsymave; 056 int sattype; 057 int eyescene; 058 int cloudscene; 059 int eyesceneold; 060 int cloudsceneold; 061 int rule9; 062 int rule8; 063 int land; 064 int eyefft; 065 int cloudfft; 066 int ringcb; 067 int ringcbval; 068 int cwring; 069 int ringcbvalmax; 070 double ringcbvalmaxlat; 071 double ringcbvalmaxlon; 072 double CIadjp; 073 int autopos; 074 int LBflag; 075 int rapiddiss; 076 double rmw; 077 double mwscore; 078 int mwdate; 079 int mwtime; 080 int r34; 081 int MSLPenv; 082 int vza; 083 String comment; 084} 085 086public class History { 087 088 private static final Logger logger = LoggerFactory.getLogger(History.class); 089 090 /** ATCF Rule 8/9 array */ 091 static String[] Rule89_ATCF = { " ", "R8", "R9", "89" }; 092 093 /** ATCF Rule 9 array */ 094 static String[] Rule9String = { "OFF", " ON", "WKN", "N/A" }; 095 096 /** rapid dissipation array */ 097 static String[] RapidDissString = { "OFF", "FLG", "ON ", "ON ", "N/A" }; 098 099 /** eye scenes */ 100 static String[] EyeSceneString = { "EYE ", "EYE/P ", "EYE/L ", "EYE/LR", "EYE/R ", "EYE/OB" }; 101 102 /** cloud scenes */ 103 static String[] CloudSceneString = { "UNIFRM", "EMBC ", "IRRCDO", "CRVBND", "SHEAR ", "EYE MW" }; 104 105 /** ATCF cloud */ 106 static String[] CloudSceneString_ATCF = { " CDO", "EMBC", "ICDO", "CBND", "SHER", "MEYE" }; 107 108 static String[] AutoPosStringAbbr = { " MAN ", "FCST ", "LAPL ", "WARM ", "SPRL ", "COMBO", 109 "EXTRP", "NETCDF", " N/A " }; 110 111 static String[] Rule8String = { "NO LIMIT ", "0.5T/6hr ", "1.0T/6hr ", "1.7T/12hr", 112 "2.2T/18hr", "2.7T/24hr", " ", " ", "0.2T/hour", "0.5T/hour", 113 "NO LIMIT ", "0.5T/6hr ", "1.0T/6hr ", "2.7T/12hr", "3.2T/18hr", "3.7T/24hr", 114 " ", " ", "0.2T/hour", "0.5T/hour", "NO LIMIT ", "0.5T/6hr ", 115 "0.7T/6hr ", "1.2T/12hr", "1.7T/18hr", "2.2T/24hr", " ", " ", 116 "0.2T/hour", "0.5T/hour", "MW Adjst ", " MW ON ", "MW ON ", "MW HOLD ", 117 "MW AdjEnd" }; 118 119 static int HISTLEN = 194; 120 121 public static int HistoryFileRecords; 122 public static IRHistoryRecord HistoryFile[] = new IRHistoryRecord[1000]; 123 public static IRHistoryRecord IRCurrentRecord = new IRHistoryRecord(); 124 125 /* 126 * public static IRHistoryRecord IRCurrentRecord = new IRHistoryRecord(); / 127 * this could be public if I redo everything 128 */ 129 130 public History() { 131 HistoryFileRecords = 0; 132 } 133 134 public void ReadHistoryFile(String filename) throws IOException { 135 String delims = "[ ]+"; 136 137 File historyfile = new File(filename); 138 Scanner in = new Scanner(historyfile); 139 140 logger.debug("Opened history file {} SUCCESSFULY", filename); 141 while (in.hasNextLine()) { 142 HistoryFile[HistoryFileRecords] = new IRHistoryRecord(); 143 String historyRec = in.nextLine(); 144 logger.debug("Parsing History file line: " + historyRec); 145 String[] tokens = historyRec.split(delims); 146 /* 147 * for(String histVals : tokens) { System.out.println(histVals); } 148 */ 149 /* 150 * HistoryFile[HistoryFileRecords].date = 151 * Integer.parseInt(tokens[0]); 152 */ 153 HistoryFile[HistoryFileRecords].date = Functions.cmonth2julian(tokens[0]); 154 HistoryFile[HistoryFileRecords].time = Integer.parseInt(tokens[1]); 155 HistoryFile[HistoryFileRecords].TrawO = Float.parseFloat(tokens[3]); 156 HistoryFile[HistoryFileRecords].Traw = Float.parseFloat(tokens[4]); 157 HistoryFile[HistoryFileRecords].Tfinal = Float.parseFloat(tokens[5]); 158 HistoryFile[HistoryFileRecords].CI = Float.parseFloat(tokens[6]); 159 HistoryFile[HistoryFileRecords].eyet = Float.parseFloat(tokens[7]); 160 HistoryFile[HistoryFileRecords].cloudt = Float.parseFloat(tokens[8]); 161 HistoryFile[HistoryFileRecords].cloudt2 = Float.parseFloat(tokens[9]); 162 HistoryFile[HistoryFileRecords].cwcloudt = Float.parseFloat(tokens[10]); 163 HistoryFile[HistoryFileRecords].latitude = Float.parseFloat(tokens[11]); 164 HistoryFile[HistoryFileRecords].longitude = Float.parseFloat(tokens[12]); 165 HistoryFile[HistoryFileRecords].eyecdosize = Float.parseFloat(tokens[13]); 166 HistoryFile[HistoryFileRecords].eyestdv = Float.parseFloat(tokens[14]); 167 HistoryFile[HistoryFileRecords].cloudsymave = Float.parseFloat(tokens[15]); 168 HistoryFile[HistoryFileRecords].sattype = Integer.parseInt(tokens[16]); 169 HistoryFile[HistoryFileRecords].eyescene = Integer.parseInt(tokens[17]); 170 HistoryFile[HistoryFileRecords].cloudscene = Integer.parseInt(tokens[18]); 171 HistoryFile[HistoryFileRecords].eyesceneold = Integer.parseInt(tokens[19]); 172 HistoryFile[HistoryFileRecords].cloudsceneold = Integer.parseInt(tokens[20]); 173 HistoryFile[HistoryFileRecords].rule9 = Integer.parseInt(tokens[21]); 174 HistoryFile[HistoryFileRecords].rule8 = Integer.parseInt(tokens[22]); 175 HistoryFile[HistoryFileRecords].LBflag = Integer.parseInt(tokens[23]); 176 HistoryFile[HistoryFileRecords].rapiddiss = Integer.parseInt(tokens[24]); 177 HistoryFile[HistoryFileRecords].land = Integer.parseInt(tokens[25]); 178 HistoryFile[HistoryFileRecords].eyefft = Integer.parseInt(tokens[26]); 179 HistoryFile[HistoryFileRecords].cloudfft = Integer.parseInt(tokens[27]); 180 HistoryFile[HistoryFileRecords].ringcb = Integer.parseInt(tokens[28]); 181 HistoryFile[HistoryFileRecords].ringcbval = Integer.parseInt(tokens[29]); 182 HistoryFile[HistoryFileRecords].cwring = Integer.parseInt(tokens[30]); 183 HistoryFile[HistoryFileRecords].autopos = Integer.parseInt(tokens[31]); 184 HistoryFile[HistoryFileRecords].CIadjp = Float.parseFloat(tokens[32]); 185 HistoryFile[HistoryFileRecords].rmw = Float.parseFloat(tokens[33]); 186 HistoryFile[HistoryFileRecords].mwscore = Float.parseFloat(tokens[34]); 187 HistoryFile[HistoryFileRecords].mwdate = Functions.cmonth2julian(tokens[35]); 188 HistoryFile[HistoryFileRecords].mwtime = Integer.parseInt(tokens[36]); 189 HistoryFile[HistoryFileRecords].r34 = Integer.parseInt(tokens[37]); 190 HistoryFile[HistoryFileRecords].MSLPenv = Integer.parseInt(tokens[38]); 191 HistoryFile[HistoryFileRecords].vza = Integer.parseInt(tokens[39]); 192 if (tokens.length > 40) { 193 if (tokens[40] != null) { 194 /* this won't get all comment past first space */ 195 HistoryFile[HistoryFileRecords].comment = tokens[40]; 196 } 197 } else { 198 HistoryFile[HistoryFileRecords].comment = ""; 199 } 200 HistoryFileRecords++; 201 } 202 in.close(); 203 logger.debug("Done reading History file, number of records: " + HistoryFileRecords); 204 } 205 206 public static int HistoryNumberOfRecords() { 207 return HistoryFileRecords; 208 } 209 210 /** 211 * List the ASCII history file between given date/times. 212 * 213 * @param OutputStyle 214 * Output one record (-1) or entire file (0). 215 * @param OutputFormatTypeID 216 * 0=ATCF, -1=History List. 217 * @param ATCFFileSourceIDString 218 * ATCF file source identifier. 219 * @param ATCFStormIDString 220 * ATCF storm identifier. 221 * 222 * @return Matching part of the ASCII history file. 223 */ 224 225 public static String ListHistory(int OutputStyle, int OutputFormatTypeID, 226 String ATCFFileSourceIDString, String ATCFStormIDString) { 227 String HistoryFileListing = ""; 228 229 boolean UseCKZTF = Env.UseCKZTF; 230 boolean Vmax1or10TF = Env.Vmax1or10TF; 231 int NumRecsHistory; 232 int DateValue; 233 int TimeValue; 234 double RawTAdj; 235 double RawTOrig; 236 double FinalT; 237 double CI; 238 double EyeTemp; 239 double CloudTemp; 240 double Latitude; 241 double Longitude; 242 int SatelliteIDValue; 243 int CloudScene; 244 int EyeScene; 245 int LandFlag; 246 int Rule8Flag; 247 int Rule9Flag; 248 int RapidDissFlag; 249 double CIPresAdj; 250 double RadiusMaxWind; 251 double MWEyeScore; 252 int AutoCenteringValue; 253 int R34Distance; 254 int EnvironMSLP; 255 double SatVZA; 256 String CommentString = null; 257 258 logger.debug("outputstyle={} outputformattype={}", OutputStyle, OutputFormatTypeID); 259 260 if (OutputStyle == 0) { 261 NumRecsHistory = HistoryNumberOfRecords(); // loop through history 262 // file 263 } else { 264 NumRecsHistory = 1; // output current record 265 } 266 267 int XInc = 0; 268 while (XInc < NumRecsHistory) { 269 if (XInc == 0) { 270 if (OutputFormatTypeID == -1) { 271 /* original format history file listing */ 272 if (UseCKZTF) { 273 HistoryFileListing += String.format(" ----Intensity--- " 274 + "-Tno Values-- ---Tno/CI Rules--- -Temperature-" 275 + " \n"); 276 } else { 277 HistoryFileListing += String 278 .format(" --------Intensity------- " 279 + "-Tno Values-- ---Tno/CI Rules--- -Temperature-" 280 + " \n"); 281 } 282 String LabelA = ""; 283 String LabelB = ""; 284 if (UseCKZTF) { 285 if (Vmax1or10TF) { 286 LabelA = String.format(" MSLP/Vmax "); 287 } else { 288 LabelA = String.format("%18s", " MSLP/Vmax10 "); 289 } 290 HistoryFileListing += String.format(" Time %18s " 291 + "Fnl Adj Ini Cnstrnt Wkng Rpd Cntr Mean " 292 + "Scene EstRMW MW Storm Location Fix\n", LabelA); 293 } else { 294 if (Vmax1or10TF) { 295 LabelB = String.format("%24s", " MSLP/MSLPLat/Vmax "); 296 } else { 297 LabelB = String.format("%24s", " MSLP/MSLPLat/Vmax10"); 298 } 299 HistoryFileListing += String.format(" Time %24s " 300 + "Fnl Adj Ini Cnstrnt Wkng Rpd Cntr Mean " 301 + "Scene EstRMW MW Storm Location Fix\n", LabelB); 302 } 303 if (UseCKZTF) { 304 HistoryFileListing += String.format(" Date (UTC) CI (CKZ)/(kts) " 305 + "Tno Raw Raw Limit Flag Wkng Region Cloud " 306 + "Type (km) Score Lat Lon Mthd Sat " 307 + "VZA Comments\n"); 308 } else { 309 HistoryFileListing += String 310 .format(" Date (UTC) CI (DvT)/BiasAdj/(kts) " 311 + "Tno Raw Raw Limit Flag Wkng Region Cloud " 312 + "Type (km) Score Lat Lon Mthd Sat " 313 + "VZA Comments\n"); 314 } 315 } else { 316 /* ATCF format listing */ 317 /* HistoryFileListing += String.format("\n"); */ 318 } 319 } 320 if (OutputStyle == 0) { 321 DateValue = HistoryFile[XInc].date; 322 TimeValue = HistoryFile[XInc].time; 323 RawTAdj = HistoryFile[XInc].Traw; 324 RawTOrig = HistoryFile[XInc].TrawO; 325 FinalT = HistoryFile[XInc].Tfinal; 326 CI = HistoryFile[XInc].CI; 327 EyeTemp = HistoryFile[XInc].eyet; 328 CloudTemp = HistoryFile[XInc].cloudt; 329 Latitude = HistoryFile[XInc].latitude; 330 Longitude = HistoryFile[XInc].longitude; 331 SatelliteIDValue = HistoryFile[XInc].sattype; 332 CloudScene = HistoryFile[XInc].cloudscene; 333 EyeScene = HistoryFile[XInc].eyescene; 334 LandFlag = HistoryFile[XInc].land; 335 Rule8Flag = HistoryFile[XInc].rule8; 336 Rule9Flag = HistoryFile[XInc].rule9; 337 RapidDissFlag = HistoryFile[XInc].rapiddiss; 338 CIPresAdj = HistoryFile[XInc].CIadjp; 339 RadiusMaxWind = HistoryFile[XInc].rmw; 340 MWEyeScore = HistoryFile[XInc].mwscore; 341 AutoCenteringValue = HistoryFile[XInc].autopos; 342 R34Distance = HistoryFile[XInc].r34; 343 EnvironMSLP = HistoryFile[XInc].MSLPenv; 344 SatVZA = ((float) HistoryFile[XInc].vza) / 10.0; 345 CommentString = String.format("%s", HistoryFile[XInc].comment); 346 } else { 347 DateValue = IRCurrentRecord.date; 348 TimeValue = IRCurrentRecord.time; 349 RawTAdj = IRCurrentRecord.Traw; 350 RawTOrig = IRCurrentRecord.TrawO; 351 FinalT = IRCurrentRecord.Tfinal; 352 CI = IRCurrentRecord.CI; 353 EyeTemp = IRCurrentRecord.eyet; 354 CloudTemp = IRCurrentRecord.cloudt; 355 Latitude = IRCurrentRecord.latitude; 356 Longitude = IRCurrentRecord.longitude; 357 SatelliteIDValue = IRCurrentRecord.sattype; 358 CloudScene = IRCurrentRecord.cloudscene; 359 EyeScene = IRCurrentRecord.eyescene; 360 LandFlag = IRCurrentRecord.land; 361 Rule8Flag = IRCurrentRecord.rule8; 362 Rule9Flag = IRCurrentRecord.rule9; 363 RapidDissFlag = IRCurrentRecord.rapiddiss; 364 CIPresAdj = IRCurrentRecord.CIadjp; 365 RadiusMaxWind = IRCurrentRecord.rmw; 366 MWEyeScore = IRCurrentRecord.mwscore; 367 AutoCenteringValue = IRCurrentRecord.autopos; 368 R34Distance = IRCurrentRecord.r34; 369 EnvironMSLP = IRCurrentRecord.MSLPenv; 370 SatVZA = ((float) IRCurrentRecord.vza) / 10.0; 371 CommentString = String.format("%s", IRCurrentRecord.comment); 372 } 373 374 boolean ListLandRecordTF = true; 375 if ((LandFlag == 1) && (CI < 1.0)) { 376 ListLandRecordTF = false; 377 } 378 379 double CIPressureValue; 380 double CIWindValue; 381 String RadiusMaxWindString = ""; 382 String MWScoreString = ""; 383 String SceneTypeString = ""; 384 if (!ListLandRecordTF) { 385 CIPresAdj = 0.0; 386 CIPressureValue = 0.0; 387 CIWindValue = 0.0; 388 SceneTypeString = String.format("LAND "); 389 Rule8Flag = 6; 390 Rule9Flag = 3; 391 RapidDissFlag = 4; 392 /* AutoCenteringValue=7; */ 393 RadiusMaxWindString = String.format(" N/A "); 394 MWScoreString = String.format(" N/A"); 395 } else { 396 Env.CKZGaleRadius = R34Distance; 397 Env.CKZPenv = EnvironMSLP; 398 CIPressureValue = Functions.adt_getpwval(0, CI, Latitude, Longitude); 399 CIWindValue = Functions.adt_getpwval(1, CI, Latitude, Longitude); 400 if (!Vmax1or10TF) { 401 /* convert 1-minute to 10-minute average Vmax for output */ 402 CIWindValue = 0.88 * CIWindValue; 403 } 404 if ((CloudScene == 3) || (CloudScene == 4)) { 405 SceneTypeString = String.format("%s", CloudSceneString[CloudScene]); 406 } else if (EyeScene < 3) { 407 SceneTypeString = String.format("%s", EyeSceneString[EyeScene]); 408 } else { 409 SceneTypeString = String.format("%s", CloudSceneString[CloudScene]); 410 } 411 if ((CloudScene <= 5) && (EyeScene <= 2)) { 412 RadiusMaxWindString = String.format("%3d IR", (int) RadiusMaxWind); 413 } else { 414 RadiusMaxWindString = String.format("%s", " N/A "); 415 } 416 if (MWEyeScore >= -99.0) { 417 MWScoreString = String.format("%5.1f", MWEyeScore); 418 } else { 419 MWScoreString = String.format("%s", " N/A"); 420 } 421 } 422 423 logger.debug("here AA {} {}", OutputFormatTypeID, NumRecsHistory); 424 if (OutputFormatTypeID == -1) { 425 /* original format history file listing */ 426 String DateString = Functions.adt_julian2cmonth(DateValue); 427 String LatLonComboString = String.format("%6.2f %7.2f", Latitude, Longitude); 428 String SatelliteIDString = Functions.adt_sattypes(SatelliteIDValue); 429 if (UseCKZTF) { 430 HistoryFileListing += String.format("%9s %06d %3.1f %6.1f %5.1f " 431 + "%3.1f %3.1f %3.1f %8s %3s %3s " 432 + "%6.2f %6.2f %6s %6s %5s %15s %5s %7s %4.1f %s\n", DateString, 433 TimeValue, CI, CIPressureValue, CIWindValue, FinalT, RawTAdj, RawTOrig, 434 Rule8String[Rule8Flag], Rule9String[Rule9Flag], 435 RapidDissString[RapidDissFlag], EyeTemp, CloudTemp, SceneTypeString, 436 RadiusMaxWindString, MWScoreString, LatLonComboString, 437 AutoPosStringAbbr[AutoCenteringValue], SatelliteIDString, SatVZA, 438 CommentString); 439 } else { 440 HistoryFileListing += String.format("%9s %06d %3.1f %6.1f %+5.1f %5.1f " 441 + "%3.1f %3.1f %3.1f %8s %3s %3s " 442 + "%6.2f %6.2f %6s %6s %5s %15s %5s %7s %4.1f %s\n", DateString, 443 TimeValue, CI, CIPressureValue + CIPresAdj, CIPresAdj, CIWindValue, 444 FinalT, RawTAdj, RawTOrig, Rule8String[Rule8Flag], 445 Rule9String[Rule9Flag], RapidDissString[RapidDissFlag], EyeTemp, 446 CloudTemp, SceneTypeString, RadiusMaxWindString, MWScoreString, 447 LatLonComboString, AutoPosStringAbbr[AutoCenteringValue], 448 SatelliteIDString, SatVZA, CommentString); 449 } 450 } else { 451 /* ATCF format listing */ 452 int RawTFlag_ATCF = OutputFormatTypeID / 1000; 453 int[] ReturnValues = Functions.adt_yddmy(DateValue); 454 int MonthValue = ReturnValues[0]; 455 int DayValue = ReturnValues[1]; 456 int YearValue = ReturnValues[2]; 457 String TimeString_ATCF = String.format("%04d", TimeValue / 100); 458 String DateString_ATCF = String.format("%4d%02d%02d%4s", YearValue, MonthValue, 459 DayValue, TimeString_ATCF); 460 String NSString_ATCF = (Latitude > 0.0) ? String.format("%s", "N") : String.format( 461 "%s", "S"); 462 String EWString_ATCF = (Longitude > 0.0) ? String.format("%s", "W") : String 463 .format("%s", "E"); 464 String LatitudeString = String.format("%4d%1s", (int) (Math.abs(Latitude) * 100), 465 NSString_ATCF); 466 String LongitudeString = String.format("%5d%1s", (int) (Math.abs(Longitude) * 100), 467 EWString_ATCF); 468 469 int StormIDNum = Integer.parseInt(ATCFStormIDString.substring(0, 2)); 470 char aChar = ATCFStormIDString.charAt(2); 471 String StormIDNumString = String.format("%02d", StormIDNum); 472 473 String BasinIDString_ATCF = ""; 474 if (aChar == 'L') { 475 BasinIDString_ATCF = String.format("%s", "AL"); 476 } else if (aChar == 'E') { 477 BasinIDString_ATCF = String.format("%s", "EP"); 478 } else if (aChar == 'C') { 479 BasinIDString_ATCF = String.format("%s", "CP"); 480 } else if (aChar == 'W') { 481 BasinIDString_ATCF = String.format("%s", "WP"); 482 } else if (aChar == 'S') { 483 BasinIDString_ATCF = String.format("%s", "SH"); 484 } else if (aChar == 'P') { 485 BasinIDString_ATCF = String.format("%s", "SH"); 486 } else if (aChar == 'U') { 487 BasinIDString_ATCF = String.format("%s", "SH"); 488 } else if (aChar == 'R') { 489 BasinIDString_ATCF = String.format("%s", "SH"); 490 } else if (aChar == 'F') { 491 BasinIDString_ATCF = String.format("%s", "SH"); 492 } else if (aChar == 'B') { 493 BasinIDString_ATCF = String.format("%s", "IO"); 494 } else if (aChar == 'A') { 495 BasinIDString_ATCF = String.format("%s", "IO"); 496 } else { 497 BasinIDString_ATCF = String.format("%s", "XX"); 498 StormIDNumString = "XX"; 499 } 500 501 int MaxWindSpeed_ATCF = (int) (CIWindValue); 502 int Pressure_ATCF = (int) (CIPressureValue + CIPresAdj); 503 int CI_ATCF = (int) ((CI + 0.01) * 10); 504 int RawTnoValue_ATCF = 0; 505 if (RawTFlag_ATCF == 0) { 506 RawTnoValue_ATCF = (int) ((RawTAdj + 0.01) * 10); /* 507 * adjusted 508 * Raw T# 509 * - 510 * default 511 */ 512 } else { 513 RawTnoValue_ATCF = (int) ((RawTOrig + 0.01) * 10); /* 514 * unadjusted 515 * Raw T# 516 */ 517 } 518 int FinalTnoValue_ATCF = (int) ((FinalT + 0.01) * 10); 519 String TnoAveTimeFlagString_ATCF = String.format("%s", "L"); 520 int TnoAveTimeFlag_ATCF = 3; /* Final T# - default */ 521 int EyeTempValue = (int) (EyeTemp); 522 int CloudTempValue = (int) (CloudTemp); 523 SceneTypeString = ""; 524 int CIConfidence = 0; 525 int WindSpeedConfidence = 0; 526 int PressureConfidence = 0; 527 int PositionConfidence = 0; 528 int Rule89Value = 0; 529 530 if (ListLandRecordTF) { 531 SceneTypeString = String.format("%s", "LAND"); 532 CIConfidence = 3; 533 WindSpeedConfidence = 3; 534 PressureConfidence = 3; 535 PositionConfidence = 2; 536 Rule89Value = 0; 537 } else { 538 Rule89Value = 0; 539 if ((Rule8Flag % 10) > 0) { 540 Rule89Value = 1; 541 } 542 if (Rule9Flag == 1) { 543 Rule89Value = 2; 544 } 545 if (((Rule8Flag % 10) > 0) && (Rule9Flag == 1)) { 546 Rule89Value = 3; 547 } 548 if ((CloudScene == 3) || (CloudScene == 4)) { 549 SceneTypeString = String.format("%s", CloudSceneString_ATCF[CloudScene]); 550 CIConfidence = 2; 551 WindSpeedConfidence = 2; 552 PressureConfidence = 2; 553 PositionConfidence = 3; 554 } else if (EyeScene < 3) { 555 SceneTypeString = String.format("%s", " EYE"); 556 CIConfidence = 1; 557 WindSpeedConfidence = 1; 558 PressureConfidence = 1; 559 PositionConfidence = 1; 560 } else { 561 SceneTypeString = String.format("%s", CloudSceneString_ATCF[CloudScene]); 562 CIConfidence = 2; 563 WindSpeedConfidence = 2; 564 PressureConfidence = 2; 565 PositionConfidence = 2; 566 } 567 } 568 String SatelliteIDString = Functions.adt_sattypes(SatelliteIDValue); 569 570 String SiteID_ATCF = String.format("%s", ATCFFileSourceIDString); 571 572 /* determine ATCF center/intensity ID */ 573 String CenterFixMethodID_ATCF = ""; 574 if (AutoCenteringValue >= 4) { 575 /* center fix by autofix method */ 576 CenterFixMethodID_ATCF = String.format("%s", "CI"); 577 } else { 578 /* center fix by forecast interpolation */ 579 if (ListLandRecordTF) { 580 /* storm is over land */ 581 CenterFixMethodID_ATCF = String.format("%s", " N"); 582 } else { 583 /* storm is over ocean */ 584 CenterFixMethodID_ATCF = String.format("%s", " I"); 585 } 586 } 587 String AutoCenterMethodString_ATCF = ""; 588 if (AutoCenteringValue == 0) { 589 AutoCenterMethodString_ATCF = String.format("%s", "MAN"); 590 } else { 591 AutoCenterMethodString_ATCF = String.format("%s", "AUT"); 592 } 593 HistoryFileListing += String.format("%2s, %2s, %12s, %3d, %4s, %10s, %1s, " 594 + "%5s, %6s, %5s, %1d, %3d, %1d, %4d, %1d, %4s, " 595 + "%3s, %4s, %4s, %4s, %4s, %4s, %1s, %1s, %1s, %1s, " 596 + "%1s, %3s, %3s, %1s, " + "%5s, %3s, %4s, %2d, %1d, %2d, " 597 + "%3d, %1s, %2d, %4d, %4d, %4s, %2s, " + "%6s, %1s, %s\n", 598 BasinIDString_ATCF, StormIDNumString, DateString_ATCF, 20, "DVTO", 599 CenterFixMethodID_ATCF, " ", LatitudeString, LongitudeString, " ", 600 PositionConfidence, MaxWindSpeed_ATCF, WindSpeedConfidence, Pressure_ATCF, 601 PressureConfidence, "DVRK", " ", " ", " ", " ", " ", " ", " ", " ", " ", 602 " ", " ", " ", " ", " ", SiteID_ATCF, AutoCenterMethodString_ATCF, " I", 603 CI_ATCF, CIConfidence, FinalTnoValue_ATCF, TnoAveTimeFlag_ATCF, 604 TnoAveTimeFlagString_ATCF, RawTnoValue_ATCF, EyeTempValue, CloudTempValue, 605 SceneTypeString, Rule89_ATCF[Rule89Value], SatelliteIDString, "T", 606 CommentString); 607 } 608 609 XInc++; 610 } 611 return HistoryFileListing; 612 } 613 614 /** 615 * Insert or overwrite a record in a history file. 616 * 617 * Global structure HistoryRecordPtr will be modified and the ASCII history 618 * file will be rewritten in another routine. 619 * 620 * @param RunFullAnalysis 621 * Full analysis toggle. 622 * @param HistoryFileName 623 * File to modify. 624 * 625 * @return Array of two integers. The first value represents the number of 626 * inserted records. The second value is flag that describes the 627 * {@literal "type"} of modification (possible values are 1, 2, 3, 628 * 4). 629 * <ol> 630 * <li>Overwritten</li> 631 * <li>Inserted</li> 632 * <li>Record placed at start of new history structure.</li> 633 * <li>Record placed at end of existing history structure.</li> 634 * </ol> 635 */ 636 // TODO(jon): document what the flags mean 637 public static int[] InsertHistoryRecord(boolean RunFullAnalysis, String HistoryFileName) { 638 639 int ModifiedCount = 0; 640 int InsertOverwriteFlag = 0; 641 boolean FoundRecordTF = false; 642 IRHistoryRecord TemporaryIRCurrentRecord = IRCurrentRecord; 643 644 boolean LandFlagTF = Env.LandFlagTF; 645 646 int NumRecsHistory = HistoryNumberOfRecords(); 647 648 int ImageDate = IRCurrentRecord.date; 649 int ImageTime = IRCurrentRecord.time; 650 double CurrentTime = Functions.calctime(ImageDate, ImageTime); 651 652 int XInc = 0; 653 while (XInc < NumRecsHistory) { 654 int RecDate = HistoryFile[XInc].date; 655 int RecTime = HistoryFile[XInc].time; 656 double HistoryRecTime = Functions.calctime(RecDate, RecTime); 657 if ((HistoryRecTime == CurrentTime) && (!FoundRecordTF)) { 658 /* OVERWRITE RECORD */ 659 logger.debug("OVERWRITE RECORD {}", XInc); 660 HistoryFile[XInc] = IRCurrentRecord; 661 FoundRecordTF = true; 662 InsertOverwriteFlag = 1; 663 } else if ((HistoryRecTime > CurrentTime) && !FoundRecordTF) { 664 /* INSERT RECORD */ 665 logger.debug("INSERT RECORD"); 666 /* shift records after HistoryRecTime up one record */ 667 NumRecsHistory++; 668 HistoryFileRecords++; 669 int YInc = HistoryFileRecords; 670 while (YInc > XInc) { 671 HistoryFile[YInc] = HistoryFile[YInc - 1]; 672 YInc--; 673 } 674 HistoryFile[XInc] = IRCurrentRecord; 675 /* 676 * System.out.printf("IRcurrentrecord.land=%d\n",IRCurrentRecord. 677 * land); 678 */ 679 FoundRecordTF = true; 680 InsertOverwriteFlag = 2; 681 } else { 682 if (FoundRecordTF) { 683 logger.debug("RECOMPUTING RECORD {}", XInc); 684 /* 685 * previously found records to insert, so all records 686 * following the inserted record must be recalculated 687 */ 688 /* 689 * assign XInc history file record as "current record" and 690 * recalculate intensity 691 */ 692 IRCurrentRecord = HistoryFile[XInc]; 693 int RecLand = HistoryFile[XInc].land; 694 double RecTnoRaw = HistoryFile[XInc].Traw; 695 if ((LandFlagTF && (RecLand == 1)) || (RecTnoRaw < 1.0)) { 696 /* assign as "missing record" */ 697 InitCurrent(false); 698 } else { 699 /* recompute intensity */ 700 Intensity.CalculateIntensity(1, RunFullAnalysis, HistoryFileName); 701 } 702 ModifiedCount++; 703 } 704 /* nothing yet... keep searching */ 705 } 706 XInc++; 707 } 708 if (!FoundRecordTF) { 709 if (XInc == 0) { 710 /* record will be placed at start of new history structure */ 711 logger.debug("PLACE RECORD AT START OF NEW"); 712 HistoryFile[0] = IRCurrentRecord; 713 InsertOverwriteFlag = 3; 714 } else { 715 /* record will be placed at end of history structure */ 716 logger.debug("PLACE RECORD AT END OF EXISTING"); 717 HistoryFile[NumRecsHistory] = IRCurrentRecord; 718 InsertOverwriteFlag = 4; 719 } 720 HistoryFileRecords++; 721 } else { 722 IRCurrentRecord = TemporaryIRCurrentRecord; 723 } 724 725 return new int[] { ModifiedCount, InsertOverwriteFlag }; 726 } 727 728 /** 729 * Delete record(s) in a history file. 730 * 731 * <p> 732 * Routine will modify structure HistoryRecordPtr, which will then be 733 * rewritten to ASCII history file in another subroutine. 734 * </p> 735 * 736 * @param RunFullAnalysis 737 * Full analysis toggle. 738 * @param HistoryFileName 739 * File to modify. 740 * 741 * @return Array containing two integer values. The first value is the 742 * number of modified records, and the seconds value is the number 743 * of deleted records. 744 */ 745 public static int[] DeleteHistoryRecords(boolean RunFullAnalysis, String HistoryFileName) { 746 int YInc = 0; 747 int ModifiedCount = 0; 748 int DeleteRecordCount = 0; 749 boolean FoundRecordTF = false; 750 IRHistoryRecord TemporaryIRCurrentRecord = IRCurrentRecord; 751 boolean LandFlagTF = Env.LandFlagTF; 752 753 int NumRecsHistory = HistoryNumberOfRecords(); 754 755 int XInc = 0; 756 int DateStart = Env.StartJulianDate; 757 int DateEnd = Env.EndJulianDate; 758 int DateStartTime = Env.StartHHMMSSTime; 759 int DateEndTime = Env.EndHHMMSSTime; 760 double AnalysisStartTime = Functions.calctime(DateStart, DateStartTime); 761 double AnalysisEndTime = Functions.calctime(DateEnd, DateEndTime); 762 763 while (XInc < NumRecsHistory) { 764 int RecDate = HistoryFile[XInc].date; 765 int RecTime = HistoryFile[XInc].time; 766 double HistoryRecTime = Functions.calctime(RecDate, RecTime); 767 768 if ((HistoryRecTime >= AnalysisStartTime) && (HistoryRecTime <= AnalysisEndTime)) { 769 /* record falls within time boundaries to delete */ 770 HistoryFileRecords--; 771 NumRecsHistory--; 772 DeleteRecordCount++; 773 YInc = XInc; 774 while (YInc < NumRecsHistory) { 775 HistoryFile[YInc] = HistoryFile[YInc + 1]; 776 YInc++; 777 } 778 FoundRecordTF = true; 779 XInc--; 780 } else { 781 /* record not within time boundaries */ 782 if (FoundRecordTF) { 783 /* 784 * previously found records to delete, so all records 785 * following the last deleted record must be recalculated 786 */ 787 IRCurrentRecord = HistoryFile[XInc]; 788 int RecLand = HistoryFile[XInc].land; 789 double RecTnoRaw = HistoryFile[XInc].Traw; 790 if (((LandFlagTF) && (RecLand == 1)) || (RecTnoRaw < 1.0)) { 791 /* assign as "missing record" */ 792 InitCurrent(false); 793 } else { 794 /* recompute intensity */ 795 Intensity.CalculateIntensity(1, RunFullAnalysis, HistoryFileName); 796 } 797 ModifiedCount++; 798 } 799 } 800 XInc++; 801 } 802 803 if (FoundRecordTF) { 804 IRCurrentRecord = TemporaryIRCurrentRecord; 805 } 806 807 return new int[] { ModifiedCount, DeleteRecordCount }; 808 } 809 810 /** 811 * Insert comment in history file at specifified date/time. 812 * 813 * @param CommentString 814 * Character string field to be inserted. 815 * 816 * @return If {@code -1}, there was an error finding record, if {@code >= 0} 817 * , number of modified records. 818 */ 819 public static int CommentHistoryRecords(String CommentString) { 820 821 int RecordCount = 0; /* record counter */ 822 boolean FoundRecordTF = false; /* found recurd logical */ 823 824 int NumRecsHistory = HistoryNumberOfRecords(); 825 826 int XInc = 0; 827 int DateStart = Env.StartJulianDate; 828 int DateEnd = Env.EndJulianDate; 829 int DateStartTime = Env.StartHHMMSSTime; 830 int DateEndTime = Env.EndHHMMSSTime; 831 double AnalysisStartTime = Functions.calctime(DateStart, DateStartTime); 832 double AnalysisEndTime = Functions.calctime(DateEnd, DateEndTime); 833 834 while (XInc < NumRecsHistory) { 835 int RecDate = HistoryFile[XInc].date; 836 int RecTime = HistoryFile[XInc].time; 837 double HistoryRecTime = Functions.calctime(RecDate, RecTime); 838 839 if ((HistoryRecTime >= AnalysisStartTime) && (HistoryRecTime <= AnalysisEndTime)) { 840 RecordCount++; 841 HistoryFile[XInc].comment = String.format("%s", CommentString); 842 FoundRecordTF = true; 843 } 844 XInc++; 845 } 846 if (!FoundRecordTF) { 847 RecordCount = -1; 848 } 849 return RecordCount; 850 } 851 852 /** 853 * Write HistoryRecordPtr structure to ASCII history file. 854 * 855 * @param HistoryFileName 856 * File to write. 857 * 858 * @return If {@code >= 0}, the value represents the number of records 859 * written. If -2, there was an error reading 860 * {@code HistoryFileName}. If {@code -3}, there was an error 861 * writing {@code HistoryFileName}. Finally, if {@code -5}, there 862 * was an error closing {@code HistoryFileName}. 863 * 864 * @throws IOException 865 * if there was a problem writing to {@code HistoryFileName}. 866 */ 867 public static int WriteHistoryFile(String HistoryFileName) throws IOException { 868 String OutputString; 869 FileWriter FileWriteStream = new FileWriter(HistoryFileName, false); 870 BufferedWriter HistoryFilePtr = new BufferedWriter(FileWriteStream); 871 872 int RecordCount = 0; /* record counter */ 873 874 int NumRecsHistory = HistoryNumberOfRecords(); 875 876 int XInc = 0; 877 while (XInc < NumRecsHistory) { 878 int RecDate = HistoryFile[XInc].date; 879 int RecTime = HistoryFile[XInc].time; 880 double HistoryRecTime = Functions.calctime(RecDate, RecTime); 881 String DateString = Functions.adt_julian2cmonth(RecDate); 882 883 int MWRecDate = HistoryFile[XInc].mwdate; 884 String MWDateString = Functions.adt_julian2cmonth(MWRecDate); 885 886 double JulianDate = HistoryRecTime - (double) ((int) HistoryRecTime / 1000) * 1000.0; 887 888 OutputString = String.format("%9s %06d %8.4f %3.1f %3.1f %3.1f %3.1f %6.2f " 889 + "%6.2f %6.2f %6.2f %6.2f %7.2f %5.1f %4.1f %4.1f " 890 + "%3d %1d %1d %2d %2d %1d %02d %1d %1d %1d %2d " 891 + "%2d %1d %2d %3d %2d %6.2f %5.1f %5.1f " + "%9s %06d %4d %4d %3d %s\n", 892 DateString, HistoryFile[XInc].time, JulianDate, HistoryFile[XInc].TrawO, 893 HistoryFile[XInc].Traw, HistoryFile[XInc].Tfinal, HistoryFile[XInc].CI, 894 HistoryFile[XInc].eyet, HistoryFile[XInc].cloudt, HistoryFile[XInc].cloudt2, 895 HistoryFile[XInc].cwcloudt, HistoryFile[XInc].latitude, 896 HistoryFile[XInc].longitude, HistoryFile[XInc].eyecdosize, 897 HistoryFile[XInc].eyestdv, HistoryFile[XInc].cloudsymave, 898 HistoryFile[XInc].sattype, HistoryFile[XInc].eyescene, 899 HistoryFile[XInc].cloudscene, HistoryFile[XInc].eyesceneold, 900 HistoryFile[XInc].cloudsceneold, HistoryFile[XInc].rule9, 901 HistoryFile[XInc].rule8, HistoryFile[XInc].LBflag, HistoryFile[XInc].rapiddiss, 902 HistoryFile[XInc].land, HistoryFile[XInc].eyefft, HistoryFile[XInc].cloudfft, 903 HistoryFile[XInc].ringcb, HistoryFile[XInc].ringcbval, 904 HistoryFile[XInc].cwring, HistoryFile[XInc].autopos, HistoryFile[XInc].CIadjp, 905 HistoryFile[XInc].rmw, Math.max(-99.5, HistoryFile[XInc].mwscore), 906 MWDateString, HistoryFile[XInc].mwtime, HistoryFile[XInc].r34, 907 HistoryFile[XInc].MSLPenv, HistoryFile[XInc].vza, HistoryFile[XInc].comment); 908 909 HistoryFilePtr.write(OutputString); 910 XInc++; 911 RecordCount++; 912 } 913 /* need to throw exception */ 914 HistoryFilePtr.close(); 915 return RecordCount; 916 } 917 918 public static void InitCurrent(boolean InitialFlagTF) { 919 if (InitialFlagTF) { 920 IRCurrentRecord.date = 1900001; 921 IRCurrentRecord.time = 0; 922 IRCurrentRecord.latitude = 999.5; 923 IRCurrentRecord.longitude = 999.5; 924 IRCurrentRecord.land = 0; 925 IRCurrentRecord.autopos = 0; 926 IRCurrentRecord.sattype = 0; 927 } 928 IRCurrentRecord.TrawO = 0.0; 929 IRCurrentRecord.Traw = 0.0; 930 IRCurrentRecord.Tfinal = 0.0; 931 IRCurrentRecord.CI = 0.0; 932 IRCurrentRecord.eyet = 99.5; 933 IRCurrentRecord.cloudt = 99.5; 934 IRCurrentRecord.cloudt2 = 99.5; 935 IRCurrentRecord.cwcloudt = 99.5; 936 IRCurrentRecord.eyecdosize = 0.0; 937 IRCurrentRecord.eyestdv = 0.0; 938 IRCurrentRecord.cloudsymave = 0.0; 939 IRCurrentRecord.eyescene = 0; 940 IRCurrentRecord.cloudscene = 0; 941 IRCurrentRecord.eyesceneold = -1; 942 IRCurrentRecord.cloudsceneold = -1; 943 IRCurrentRecord.rule9 = 0; 944 IRCurrentRecord.rule8 = 0; 945 IRCurrentRecord.LBflag = 0; 946 IRCurrentRecord.rapiddiss = 0; 947 IRCurrentRecord.eyefft = 0; 948 IRCurrentRecord.cloudfft = 0; 949 IRCurrentRecord.ringcb = 0; 950 IRCurrentRecord.ringcbval = 0; 951 IRCurrentRecord.cwring = 0; 952 IRCurrentRecord.CIadjp = 0.0; 953 IRCurrentRecord.rmw = -99.5; 954 IRCurrentRecord.mwscore = -99.5; 955 IRCurrentRecord.mwdate = 1900001; 956 IRCurrentRecord.mwtime = 0; 957 IRCurrentRecord.r34 = -99; 958 IRCurrentRecord.MSLPenv = -999; 959 IRCurrentRecord.vza = 0; 960 IRCurrentRecord.comment = ""; 961 } 962}