From f30c30c494d2fc5aa67545b81c8aeccc9b40064d Mon Sep 17 00:00:00 2001 From: Sarah Pontius Date: Thu, 21 May 2015 15:51:38 -0600 Subject: [PATCH 1/3] VLab Issue #8327 - Issue with HLS if storm is stationary; fixes #8327 Change-Id: I54d0740a09530a026565fc5ee13c7fa82e29ab20 Former-commit-id: 241aadab209b03647f761115958e0628b2611794 --- .../edex_static/base/textproducts/templates/product/HLS.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/HLS.py b/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/HLS.py index d64010c884..5f00117808 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/HLS.py +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/HLS.py @@ -1,4 +1,4 @@ -# Version 2015.2.12-1 +# Version 2015.5.21-0 import GenericHazards import string, time, os, re, types, copy, LogStream, collections @@ -23,7 +23,7 @@ class TextProduct(HLSTCV_Common.TextProduct): Definition["database"] = "Official" # Source database Definition["debug"] = 1 Definition["mapNameForCombinations"] = "Zones_" - Definition["defaultEditAreas"] = "Combinations_HLS_" + Definition["defaultEditAreas"] = "" Definition["showZoneCombiner"] = 0 # 1 to cause zone combiner to display Definition["productName"] = "LOCAL STATEMENT" @@ -1560,7 +1560,7 @@ class TextProduct(HLSTCV_Common.TextProduct): self._stormTypeName = self._stormType + " " + self._stormName self._decodeStormInfo(stormDict) # Storm movement in mph and the stated movement trend - self._stormMovementTrend = self._expandBearings("Moving " + stormDict.get("StormMotion","")) + self._stormMovementTrend = self._expandBearings("Movement " + stormDict.get("StormMotion","")) # Storm intensity in mph and the stated intensity trend. self._stormIntensityTrend = "Storm Intensity " + stormDict.get("StormIntensity","") From b5ac7fef0bc8dde2701c771343a86259067ca034 Mon Sep 17 00:00:00 2001 From: Ana Rivera Date: Thu, 21 May 2015 14:28:58 +0000 Subject: [PATCH 2/3] VLab Issue #8326 - DR17492 A new TCStormSurgeThreat procedure; fixes #8326 Change-Id: I70b38b4e6c21372a4522446e94e370e90e342334 Former-commit-id: bd4722e28a60504f610350ccc7c0b6eb9cd6898e --- .../procedures/TCStormSurgeThreat.py | 304 ++++++++++++------ 1 file changed, 204 insertions(+), 100 deletions(-) diff --git a/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCStormSurgeThreat.py b/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCStormSurgeThreat.py index d6ca7724cf..449216e5c2 100644 --- a/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCStormSurgeThreat.py +++ b/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/TCStormSurgeThreat.py @@ -16,9 +16,14 @@ # Aug 13, 2014: To rename SurgeHtPlustTide to InundationMax and incorporate InundationTiming. PS # Sept 17, 2014: To finalize changes and clean up for 2015initial Baseline Check in. # -# Last Modified: Sept 18, 2014: Added code to pull grids from NHC via ISC if PHISH not +# Sept 18, 2014: Added code to pull grids from NHC via ISC if PHISH not # Available on time. Left inactive (commented out) for the moment until that can be fully tested later # in 2014 or in 2015. +# +# Last Modified: May 18, 2015 (LEFebvre/Santos): Added option to create null grids and manual grids when +# PSURGE not available. Added checks for current guidance for PHISH and ISC options. +# +# Last Modified May 21, 2015 (LeFebvre): Changes made based on code review suggestions. # # ---------------------------------------------------------------------------- # The MenuItems list defines the GFE menu item(s) under which the @@ -43,17 +48,27 @@ VariableList = [("DEFAULT: Typical. Should only be changed in coordination with "Higher (40% Exceedance; for well-behaved systems within 6 hours of the event)", "Highest (50% Exceedance; for well-behaved systems at time of the event)"]), ("Grid Smoothing?", "Yes", "radio", ["Yes","No"]), - ("Make grids from PHISH\n or ISC?\n", "PHISH", "radio", ["PHISH", "ISC"]), + ("Make grids from \nPHISH, ISC, or Manually?", "PHISH", "radio", ["PHISH", "ISC", "Manually"]), + ("Manual Inundation settings:", "", "label"), + ("Inundation Height:", 1.0, "scale", [0.0, 2.5], 0.5), + ("Start Hour for Inundation Timing", 0, "scale", [0.0, 72.0], 6.0), + ("End Hour for Inundation Timing", 6, "scale", [0.0, 78.0], 6.0), ] +MetersToFeet = 3.281 +MinValue = -80.0 + class Procedure (SmartScript.SmartScript): def __init__(self, dbss): SmartScript.SmartScript.__init__(self, dbss) def getWEInventory(self, modelName, WEName, level): allTimes = TimeRange.allTimes().toJavaObj() - gridInfo = self.getGridInfo(modelName, WEName, level, allTimes) trList = [] + try: + gridInfo = self.getGridInfo(modelName, WEName, level, allTimes) + except: + return trList for g in gridInfo: start = g.gridTime().startTime().unixTime() end = g.gridTime().endTime().unixTime() @@ -62,6 +77,12 @@ class Procedure (SmartScript.SmartScript): trList.append(tr) return trList + + def baseGuidanceTime(self): + startTime = int((self._gmtime().unixTime() - (2 * 3600)) / (6 * 3600)) * (6 * 3600) + + return startTime + def getAvgTopoGrid(self, topodb): @@ -84,7 +105,7 @@ class Procedure (SmartScript.SmartScript): # convert to feet - topoGrid = topoGrid * 3.281 + topoGrid = topoGrid * MetersToFeet #topoVal = topoGrid.copy() min = -16000 max = 16000.0 @@ -95,7 +116,7 @@ class Procedure (SmartScript.SmartScript): # mask1 = topoVal< min # mask2 = topoVal> max -# topoGrid = np.where(mask1,-80.0,topoVal) +# topoGrid = np.where(mask1,MinValue,topoVal) # topoGrid = np.where(mask2,self.getTopo(),topoVal) return topoGrid @@ -105,7 +126,6 @@ class Procedure (SmartScript.SmartScript): cTime = int(self._gmtime().unixTime()/ 3600) * 3600 startTime = AbsTime.AbsTime(cTime) endTime = startTime + (hours * 3600) - threatTR = TimeRange.TimeRange(startTime, endTime) timeRange = TimeRange.TimeRange(startTime, endTime) return timeRange @@ -132,25 +152,32 @@ class Procedure (SmartScript.SmartScript): modelIDList.sort() if len(modelIDList) == 0: - self.statusBarMsg("No pSurge data found in your inventory.", "S") - return None, None, None + self.statusBarMsg("No pSurge databases found in your inventory.", "S") + return None - # the last one is the latest -# modelIDList[-1] surgeModel = modelIDList[-1] weName = "Surge" + pctStr + "Pct" trList = self.getWEInventory(dbName, weName, level) + + if len(trList) == 0: + self.statusBarMsg("No grids were found in the latest database " + str(surgeModel), "A") + return None + + #baseTime = self.getBaseGuidanceTime() + (6 * 3600) # model data will be offset 6 hours + baseTime = self.baseGuidanceTime() + (6 * 3600) # model data will be offset 6 hours + + if baseTime > trList[0].startTime().unixTime(): + self.statusBarMsg("TPCSurgeProb database is not current. Aborting", "A") + return None + + grid = self.getGrids(dbName, weName, level, trList[0], mode="Max") - #print "Retreiving ", weName, " at ", level - for tr in trList: - grid = self.getGrids(dbName, weName, level, tr, mode="Max") - #maxGrid = maximum(grid, -100.0) # calculate the max as we go surgeVal = grid.copy() - mask = surgeVal>-100 - grid = np.where(mask,surgeVal*3.28, -80.0) -# print dir(grid) + mask = surgeVal > -100 + grid = np.where(mask,surgeVal*MetersToFeet, MinValue) + return grid # convert meters to feet def makePhishGrid(self, pctStr, level, smoothThreatGrid): @@ -168,6 +195,8 @@ class Procedure (SmartScript.SmartScript): n = 1 for tr in trList: + # Make a timeRange that starts a few days in the past and ends a few days in the future + # so we can be sure all the old grids are deleted. start = tr.startTime().unixTime() - 6*3600 if n == 1: starttimeghls = tr.startTime().unixTime() - 3*3600 @@ -187,9 +216,9 @@ class Procedure (SmartScript.SmartScript): continue if smoothThreatGrid is "Yes": - phishGrid = np.where(np.greater(phishGrid, 0.0), self.smoothGrid(phishGrid,3), phishGrid) + phishGrid[phishGrid>0.0] = self.smoothGrid(phishGrid,3) - grid = np.where(phishGrid>-100,phishGrid*3.28, -80.0) + grid = np.where(phishGrid>-100,phishGrid*MetersToFeet, MinValue) self.createGrid("Fcst", "InundationTiming", "SCALAR", grid, tr6, precision=1) return @@ -216,10 +245,10 @@ class Procedure (SmartScript.SmartScript): grid = self.getGrids(dbName, weName, "SFC", tr, mode="First") #maxGrid = maximum(grid, -100.0) # calculate the max as we go - #maxGrid = where(greater(maxGrid,-100.0), maxGrid*3.28, maxGrid) + #maxGrid = where(greater(maxGrid,-100.0), maxGrid*MetersToFeet, maxGrid) conversionGrid = grid.copy() mask = conversionGrid>-0.40 - grid = np.where(mask, conversionGrid*3.28, -80.0) + grid = np.where(mask, conversionGrid*MetersToFeet, MinValue) #return maxGrid # convert meters to feet return grid @@ -246,10 +275,10 @@ class Procedure (SmartScript.SmartScript): grid = self.getGrids(dbName, weName, "SFC", tr, mode="First") #maxGrid = maximum(grid, -100.0) # calculate the max as we go - #maxGrid = where(greater(maxGrid,-100.0),maxGrid*3.28, maxGrid) + #maxGrid = where(greater(maxGrid,-100.0),maxGrid*MetersToFeet, maxGrid) conversionGrid = grid.copy() mask = conversionGrid>0.0 - grid = np.where(mask,conversionGrid *3.28, -80.0) + grid = np.where(mask,conversionGrid *MetersToFeet, MinValue) #return maxGrid # convert meters to feet return grid @@ -276,10 +305,10 @@ class Procedure (SmartScript.SmartScript): grid = self.getGrids(dbName, weName, "SFC", tr, mode="First") #maxGrid = maximum(grid, -100.0) # calculate the max as we go - #maxGrid = where(greater(maxGrid,-100.0),maxGrid*3.28, maxGrid) + #maxGrid = where(greater(maxGrid,-100.0),maxGrid*MetersToFeet, maxGrid) conversionGrid = grid.copy() mask = conversionGrid>-3.09 - grid = np.where(mask, conversionGrid*3.28, -80.0) + grid = np.where(mask, conversionGrid*MetersToFeet, MinValue) #return maxGrid # convert meters to feet return grid @@ -305,10 +334,10 @@ class Procedure (SmartScript.SmartScript): grid = self.getGrids(dbName, weName, "SFC", tr, mode="First") #maxGrid = maximum(grid, -100.0) # calculate the max as we go - #maxGrid = where(greater(maxGrid,-100.0),maxGrid*3.28, maxGrid) + #maxGrid = where(greater(maxGrid,-100.0),maxGrid*MetersToFeet, maxGrid) conversionGrid=grid.copy() mask = conversionGrid>-2.20 - grid = np.where(mask, conversionGrid*3.28, -80.0) + grid = np.where(mask, conversionGrid*MetersToFeet, MinValue) #return maxGrid # convert meters to feet return grid @@ -335,10 +364,10 @@ class Procedure (SmartScript.SmartScript): grid = self.getGrids(dbName, weName, "SFC", tr, mode="First") #maxGrid = maximum(grid, -100.0) # calculate the max as we go - #maxGrid = where(greater(maxGrid,-100.0),maxGrid*3.28, maxGrid) + #maxGrid = where(greater(maxGrid,-100.0),maxGrid*MetersToFeet, maxGrid) conversionGrid = grid.copy() mask = conversionGrid>-3.40 - grid = np.where(mask, conversionGrid*3.28, -80.0) + grid = np.where(mask, conversionGrid*MetersToFeet, MinValue) #return maxGrid # convert meters to feet return grid @@ -347,11 +376,11 @@ class Procedure (SmartScript.SmartScript): # factors of less than 3 are useless or dangerous if factor < 3: return grid - st = time.time() + half = int(factor)/ 2 - sg = np.zeros(grid.shape,"f8") - count = np.zeros(grid.shape,"f8") - gridOfOnes = np.ones(grid.shape,"f8") + sg = np.zeros(grid.shape,"f4") + count = np.zeros(grid.shape,"f4") + gridOfOnes = np.ones(grid.shape,"f4") for y in range(-half, half + 1): for x in range(-half, half + 1): if y < 0: @@ -375,27 +404,25 @@ class Procedure (SmartScript.SmartScript): target = [yTargetSlice, xTargetSlice] src = [ySrcSlice, xSrcSlice] - sg[target] = np.where(np.greater(grid[src],-80.0),sg[target] + grid[src],sg[target]) - count[target] = np.where(np.greater(grid[src],-80.0),count[target] + gridOfOnes[src],count[target]) + sg[target] = np.where(np.greater(grid[src],MinValue),sg[target] + grid[src],sg[target]) + count[target] = np.where(np.greater(grid[src],MinValue),count[target] + gridOfOnes[src],count[target]) - return np.where(np.greater(count,0.0), sg / count, -80.0) + return np.where(np.greater(count,0.0), sg / count, MinValue) # Copies the specified weather elements in elementList into the Fcst database. def copyISCGridstoFcst(self, elementList): - # First delete the existing grids so there's no confusion - cTime = int(self._gmtime().unixTime()/ 3600) * 3600 - startTime = AbsTime.AbsTime(cTime - 24*3600) - endTime = startTime + 240*3600 - timeRange = TimeRange.TimeRange(startTime, endTime) - + # Initialize all the grids we plan to return + + surgePctGrid = None + surgePctGridMSL = None + surgePctGridMLLW = None + surgePctGridMHHW = None + surgePctGridNAVD = None + + baseTime = self.baseGuidanceTime() - for elem in elementList: - if elem == "InundationTiming": - #print "Deleting: ", elem - self.deleteCmd([elem], timeRange) - for weName in elementList: iscWeName = weName + "nc" # get the inventory for the ISC grids @@ -403,12 +430,23 @@ class Procedure (SmartScript.SmartScript): trList = self.getWEInventory("ISC", iscWeName, "SFC") except: self.statusBarMsg("No grids found in ISC database for " + iscWeName, "S") - continue + return None, None, None, None, None if len(trList) == 0: self.statusBarMsg("No grids found in ISC database for " + iscWeName, "S") - continue + return None, None, None, None, None + # Make sure that the ISC grids are current + if baseTime > trList[0].startTime().unixTime(): + #if trList[0].startTime().unixTime() != baseTime: + self.statusBarMsg("ISC grids for element " + weName + " are not current. Aborting.", "S") + return None, None, None, None, None + + # If we made it this far, delete the existing grids so there's no confusion + if weName == "InundationTiming": + timeRange = TimeRange.allTimes() + self.deleteCmd(["InundationTiming"], timeRange) + # Fetch the ISC grid and create the same grid in the Fcst database for tr in trList: grid = self.getGrids("ISC", iscWeName, "SFC", tr) @@ -423,22 +461,45 @@ class Procedure (SmartScript.SmartScript): elif iscWeName == "SurgeHtPlusTideMHHWnc": surgePctGridMHHW = grid elif iscWeName == "SurgeHtPlusTideNAVDnc": - surgePctGridNAVD = grid + surgePctGridNAVD = grid return surgePctGrid,surgePctGridMSL,surgePctGridMLLW,surgePctGridMHHW,surgePctGridNAVD - def execute(self, varDict): + # Make a list of timeRanges that will be used to make InundationTiming grids + def makeTimingTRs(self, baseTime): + # Make the inundation timing grids + trList = [] + for t in range(0, 78, 6): + start = baseTime + t * 3600 + end = baseTime + (t + 6) * 3600 + tr = TimeRange.TimeRange(AbsTime.AbsTime(start), AbsTime.AbsTime(end)) + trList.append(tr) + + return trList + + def getTimingGrids(self): + + baseTime = self.baseGuidanceTime() + gridList = [] + trList = self.makeTimingTRs(baseTime) + + for tr in trList: + timingGrid = np.zeros(self.getGridShape(), np.float32) + gridList.append(timingGrid) + + return trList, gridList + + def execute(self, varDict, editArea): # List of elements # See if we should copy from ISC. If so, do the copy and exit smoothThreatGrid = varDict["Grid Smoothing?"] - PHISHorISC = varDict["Make grids from PHISH\n or ISC?\n"] - #PHISHorISC = "PHISH" + makeOption = varDict["Make grids from \nPHISH, ISC, or Manually?"] topodb = "NED" #topodb = varDict["Topographic Database?"] - editArea = self.getEditArea("StormSurgeWW_EditArea") - ssea = self.encodeEditArea(editArea) + stormSurgeEditArea = self.getEditArea("StormSurgeWW_EditArea") + ssea = self.encodeEditArea(stormSurgeEditArea) Topo = self.getAvgTopoGrid(topodb) @@ -450,7 +511,7 @@ class Procedure (SmartScript.SmartScript): #print "pctStr is: ", pctStr - if PHISHorISC == "PHISH": + if makeOption == "PHISH": #initialize grids to zero surgePctGrid = self._empty @@ -459,6 +520,10 @@ class Procedure (SmartScript.SmartScript): # Now get the psurge surgePctGrid = self.getExceedanceHeight(pctStr, "FHAG0") surgePctGridNAVD = self.getExceedanceHeight(pctStr, "SFC") + + if surgePctGrid is None or surgePctGridNAVD is None: + return + #print "retrieved my grids" # # The following lines are the gridded vdatum corrections. @@ -478,23 +543,63 @@ class Procedure (SmartScript.SmartScript): surgePctGrid = np.where(np.greater(surgePctGrid, 0.0), self.smoothGrid(surgePctGrid,3), surgePctGrid) surgePctGridNAVD = np.where(np.greater(surgePctGridNAVD, -10.0), self.smoothGrid(surgePctGridNAVD,3), surgePctGridNAVD) - mask1 = np.logical_and(np.greater(msltonavd, -80.0),np.greater(surgePctGridNAVD,-80.0)) - surgePctGridMSL= np.where(mask1, surgePctGridNAVD - msltonavd, -80.0) # MSL Grid - surgePctGridMLLW = np.where(np.greater(navdtomllw,-80.0) & np.greater(surgePctGridNAVD,-80.0), \ - surgePctGridNAVD + navdtomllw, -80.0)# MLLW Grid - surgePctGridMHHW = np.where(np.greater(navdtomhhw,-80.0) & np.greater(surgePctGridNAVD,-80.0), \ - surgePctGridNAVD + navdtomhhw, -80.0)# MHHW Grid - surgeDiffMLLWMHHW = np.where(np.greater(surgePctGridMLLW,-80.0) & np.greater(surgePctGridMHHW, -80.0), \ - surgePctGridMLLW-surgePctGridMHHW, -80.0)# Diff Grid Between MLLW and MHHW + mask1 = np.logical_and(np.greater(msltonavd, MinValue),np.greater(surgePctGridNAVD,MinValue)) + surgePctGridMSL= np.where(mask1, surgePctGridNAVD - msltonavd, MinValue) # MSL Grid + surgePctGridMLLW = np.where(np.greater(navdtomllw,MinValue) & np.greater(surgePctGridNAVD,MinValue), \ + surgePctGridNAVD + navdtomllw, MinValue)# MLLW Grid + surgePctGridMHHW = np.where(np.greater(navdtomhhw,MinValue) & np.greater(surgePctGridNAVD,MinValue), \ + surgePctGridNAVD + navdtomhhw, MinValue)# MHHW Grid + surgeDiffMLLWMHHW = np.where(np.greater(surgePctGridMLLW,MinValue) & np.greater(surgePctGridMHHW, MinValue), \ + surgePctGridMLLW-surgePctGridMHHW, MinValue)# Diff Grid Between MLLW and MHHW self.makePhishGrid(pctStr, "FHAG0", smoothThreatGrid) - else: + elif makeOption == "ISC": elementList = ["InundationMax","InundationTiming", "SurgeHtPlusTideMSL","SurgeHtPlusTideMLLW", "SurgeHtPlusTideNAVD","SurgeHtPlusTideMHHW"] surgePctGrid,surgePctGridMSL,surgePctGridMLLW,surgePctGridMHHW,surgePctGridNAVD = self.copyISCGridstoFcst(elementList) + if surgePctGrid is None or surgePctGridMSL is None or surgePctGridMLLW is None or \ + surgePctGridMHHW is None or surgePctGridNAVD is None: + return + elif makeOption == "Manually": + inundationHeight = float(varDict["Inundation Height:"]) + inunStartHour = float(varDict["Start Hour for Inundation Timing"]) + inunEndHour = float(varDict["End Hour for Inundation Timing"]) + + # Calculate the intersection of the SSEditArea and selected editArea + selectedMask = self.encodeEditArea(editArea) + if not selectedMask.any(): + self.statusBarMsg("Please define an area over which to assign the inundation value.", "S") + return + + if inunStartHour >= inunEndHour: + self.statusBarMsg("Please define the end hour after the start hour.", "S") + return + + timeRange = TimeRange.allTimes() + self.deleteCmd(["InundationTiming"], timeRange) + modifyMask = selectedMask & ssea + + # make the InundationMax grid + surgePctGrid = np.zeros(self.getGridShape(), np.float32) + surgePctGrid[modifyMask] = inundationHeight + # Make the timing grids + baseTime = self.baseGuidanceTime() +# trList = self.makeTimingTRs(baseTime) + trList, timingGrids = self.getTimingGrids() + + for i in range(len(trList)): + # only modify grid in the specified time range + start = trList[i].startTime().unixTime() + end = trList[i].endTime().unixTime() + + if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour: + timingGrids[i][modifyMask] = inundationHeight # populate where needed + + self.createGrid("Fcst", "InundationTiming", "SCALAR", timingGrids[i], trList[i]) + threatWEName = "StormSurgeThreat" threatKeys = self.getDiscreteKeys(threatWEName) @@ -510,12 +615,7 @@ class Procedure (SmartScript.SmartScript): threshDict = {} # a dict to store thresholds from the UI for key in keyMap.keys(): - # if not key in varDict.keys(): # This should never happen - # print "Error in mapping UI keys to DISCRETE keys." - # print "Please fix the keyMap dictionary." - # return - #threshDict[keyMap[key]] = varDict[key] if keyMap[key] == "Extreme": threshDict[keyMap[key]] = 9 elif keyMap[key] == "High": @@ -527,8 +627,39 @@ class Procedure (SmartScript.SmartScript): #print "threshDict[keyMap[key]]: ", keyMap[key], threshDict[keyMap[key]] + # make a timeRange - 6 hours long + elementList = ["StormSurgeThreat","InundationMax","SurgeHtPlusTideMSL","SurgeHtPlusTideMLLW", + "SurgeHtPlusTideNAVD","SurgeHtPlusTideMHHW"] + + # make a new timeRange that will be used to create new grids + timeRange = self.makeNewTimeRange(6) + + # Remove old guidance grids and replace them with the new grids + # Delete the old grids first + cTime = int(self._gmtime().unixTime()/ 3600) * 3600 + startTime = AbsTime.AbsTime(cTime - 24*3600) + endTime = startTime + 240*3600 + deleteTimeRange = TimeRange.TimeRange(startTime, endTime) + + for elem in elementList: + self.deleteCmd([elem], deleteTimeRange) + + # display the D2D grid for debugging purposes only + self.createGrid("Fcst", "InundationMax", "SCALAR", surgePctGrid, + timeRange, precision=2) + + if makeOption != "Manually": + self.createGrid("Fcst", "SurgeHtPlusTideMSL", "SCALAR", surgePctGridMSL, + timeRange, precision=2) + self.createGrid("Fcst", "SurgeHtPlusTideMLLW", "SCALAR", surgePctGridMLLW, + timeRange, precision=2) + self.createGrid("Fcst", "SurgeHtPlusTideNAVD", "SCALAR", surgePctGridNAVD, + timeRange, precision=2) + self.createGrid("Fcst", "SurgeHtPlusTideMHHW", "SCALAR", surgePctGridMHHW, + timeRange, precision=2) + # make a grid of zeros. This will be the CoastalThreat grid - coastalThreat = np.zeros(self.getTopo().shape) + coastalThreat = np.zeros(self.getGridShape(), np.float32) # Yet another list to define the order in which we set grid values # This order must be ranked lowest to highest @@ -541,35 +672,7 @@ class Procedure (SmartScript.SmartScript): thresh = threshDict[key] keyIndex = self.getIndex(key, threatKeys) coastalThreat = np.where(ssea & np.greater_equal(surgePctGrid, thresh), keyIndex, - coastalThreat) - - # make a timeRange - 6 hours long - elementList = ["StormSurgeThreat","InundationMax","SurgeHtPlusTideMSL","SurgeHtPlusTideMLLW","SurgeHtPlusTideNAVD","SurgeHtPlusTideMHHW"] - - cTime = int(self._gmtime().unixTime()/ 3600) * 3600 - startTime = AbsTime.AbsTime(cTime - 24*3600) - endTime = startTime + 240*3600 - timeRange = TimeRange.TimeRange(startTime, endTime) - #print "time range to delete is: ", timeRange - - for elem in elementList: - #print "Deleting: ", elem - self.deleteCmd([elem], timeRange) - - timeRange = self.makeNewTimeRange(6) - - # display the D2D grid for debugging purposes only - self.createGrid("Fcst", "InundationMax", "SCALAR", surgePctGrid, - timeRange, precision=2) - self.createGrid("Fcst", "SurgeHtPlusTideMSL", "SCALAR", surgePctGridMSL, - timeRange, precision=2) - self.createGrid("Fcst", "SurgeHtPlusTideMLLW", "SCALAR", surgePctGridMLLW, - timeRange, precision=2) - self.createGrid("Fcst", "SurgeHtPlusTideNAVD", "SCALAR", surgePctGridNAVD, - timeRange, precision=2) - self.createGrid("Fcst", "SurgeHtPlusTideMHHW", "SCALAR", surgePctGridMHHW, - timeRange, precision=2) - + coastalThreat) # create the CoastalThreat Grid self.createGrid("Fcst", threatWEName, "DISCRETE", @@ -580,3 +683,4 @@ class Procedure (SmartScript.SmartScript): defaultColorTable="Hazards") return + From 33a5f527fb2cc5e5f710b1ecd2d6e7e026870fdd Mon Sep 17 00:00:00 2001 From: Ana Rivera Date: Fri, 22 May 2015 15:58:50 +0000 Subject: [PATCH 3/3] VLab Issue #8325 - DR17502 WFO TCV can fail due to InundationMax and InundationTiming differences; fixes #8325 Change-Id: I363f2bdb7694a504ac907ee0e99f06712d314c0b Former-commit-id: ed825a5536074139ad20d83d0f34ac667a33f516 --- .../templates/product/Hazard_TCV.py | 116 +++--------------- 1 file changed, 18 insertions(+), 98 deletions(-) diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/Hazard_TCV.py b/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/Hazard_TCV.py index 72d8cfc7d7..fa6ad9836c 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/Hazard_TCV.py +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/utility/edex_static/base/textproducts/templates/product/Hazard_TCV.py @@ -1,4 +1,4 @@ -# Version 2015.2.13-0 +# Version 2015.5.22-0 import GenericHazards import JsonSupport @@ -19,7 +19,6 @@ class TextProduct(HLSTCV_Common.TextProduct): Definition["displayName"] = "None" Definition["outputFile"] = "{prddir}/TEXT/TCV.txt" Definition["database"] = "Official" # Source database - Definition["debug"] = 1 Definition["mapNameForCombinations"] = "Zones_" Definition["defaultEditAreas"] = "Combinations_TCV_" Definition["showZoneCombiner"] = 1 # 1 to cause zone combiner to display @@ -1490,13 +1489,10 @@ class SectionCommon(): if self._tr is not None: specialStatements = self._specialImpactsStatements() if self._tr in specialStatements.keys(): - if self._tr == "default": - return specialStatements[self._tr][maxThreat] + if self._tr == "recovery" and not self.isThreatInAllAdvisories: + return [] else: - if self._tr == "recovery" and not self.isThreatInAllAdvisories: - return [] - else: - return specialStatements[self._tr] + return specialStatements[self._tr] import TCVDictionary potentialImpactStatements = TCVDictionary.PotentialImpactStatements @@ -1507,19 +1503,27 @@ class SectionCommon(): segment, vtecRecords = productSegment - self._textProduct.debug_print("zone number = %s, elementName = %s, maxThreat = %s" % - (segment, elementName, maxThreat), 1) + self._textProduct.debug_print("zone number = %s, elementName = %s, maxThreat = %s, tr = %s" % + (segment, elementName, maxThreat, self._tr), 1) if segment in tcv_AreaDictionary: potentialImpactStatements = tcv_AreaDictionary[segment]["potentialImpactsStatements"] - + # Check for any overrides try: statements = potentialImpactStatements[elementName][maxThreat] except KeyError: pass - - return statements + + # If this is the "default" case + if self._tr == "default" and len(statements) > 0: + + if elementName in ["Wind", "Storm Surge"]: + if statements[0].find("If realized, ") == -1: + statements[0] = "If realized, " + statements[0] + \ + statements[0][1:] + + return statements # Specific hazard sections can override this to provide special impacts statements def _specialImpactsStatements(self): @@ -1687,29 +1691,6 @@ class WindSection(SectionCommon): ], "recovery": ["Little to no additional wind impacts expected. Community officials are now assessing the extent of actual wind impacts accordingly.", ], - "default": {"Extreme": ["If realized, major hurricane force wind can cause structural damage to sturdy buildings, some with complete roof and wall failures. Complete destruction of mobile homes. Damage greatly accentuated by large airborne projectiles. Locations may be uninhabitable for weeks or months.", - "Numerous large trees snapped or uprooted along with fences and roadway signs blown over.", - "Many roads impassable from large debris, and more within urban or heavily wooded places. Many bridges, causeways, and access routes impassable.", - "Widespread power and communication outages.", - ], - "High": ["If realized, hurricane force wind can cause considerable roof damage to sturdy buildings, with some having window, door, and garage door failures leading to structural damage. Mobile homes severely damaged, with some destroyed. Damage accentuated by airborne projectiles. Locations may be uninhabitable for weeks.", - "Many large trees snapped or uprooted along with fences and roadway signs blown over.", - "Some roads impassable from large debris, and more within urban or heavily wooded places. Several bridges, causeways, and access routes impassable.", - "Large areas with power and communications outages.", - ], - "Mod": ["If realized, strong tropical storm force wind can cause some damage to roofing and siding materials, along with damage to porches, awnings, carports, and sheds. A few buildings experiencing window, door, and garage door failures. Mobile homes damaged, especially if unanchored. Unsecured lightweight objects become dangerous projectiles.", - "Several large trees snapped or uprooted, but with greater numbers in places where trees are shallow rooted. Several fences and roadway signs blown over.", - "Some roads impassable from large debris, and more within urban or heavily wooded places. A few bridges, causeways, and access routes connecting barrier islands impassable.", - "Scattered power and communications outages, but more prevalent in areas with above ground lines.", - ], - "Elevated": ["If realized, tropical storm force wind can cause damage to porches, awnings, carports, sheds, and unanchored mobile homes. Unsecured lightweight objects blown about.", - "Many large tree limbs broken off. A few trees snapped or uprooted, but with greater numbers in places where trees are shallow rooted. Some fences and roadway signs blown over.", - "A few roads impassable from debris, particularly within urban or heavily wooded places. Hazardous driving conditions on bridges and other elevated roadways.", - "Scattered power and communications outages.", - ], - "None": ["Little to no potential impacts from wind.", - ] - } } ### Supporting functions @@ -1878,29 +1859,6 @@ class StormSurgeSection(SectionCommon): ], "recovery": ["Little to no additional surge impacts expected. Community officials are now assessing the extent of actual surge impacts accordingly.", ], - "default": {"Extreme": ["If realized, extreme storm surge flooding can cause widespread deep inundation accentuated by powerful battering waves. Structural damage to buildings, with many washing away. Damage greatly compounded from considerable floating debris. Locations may be uninhabitable for an extended period.", - "Near-shore escape routes and secondary roads washed out or severely flooded. Flood control systems and barriers may become stressed.", - "Extreme beach erosion. New shoreline cuts possible.", - "Massive damage to marinas, docks, boardwalks, and piers. Numerous small craft broken away from moorings with many lifted onshore and stranded.", - ], - "High": ["If realized, major storm surge flooding can cause large areas of deep inundation accentuated by battering waves. Structural damage to buildings, with several washing away. Damage compounded by floating debris. Locations may be uninhabitable for an extended period.", - "Large sections of near-shore escape routes and secondary roads washed out or severely flooded. Flood control systems and barriers may become stressed.", - "Severe beach erosion with significant dune loss.", - "Major damage to marinas, docks, boardwalks, and piers. Many small craft broken away from moorings, especially in unprotected anchorages with some lifted onshore and stranded.", - ], - "Mod": ["If realized, moderate storm surge flooding can cause areas of inundation accentuated by large waves. Damage to several buildings, mainly near the coast.", - "Sections of near-shore escape routes and secondary roads become weakened or washed out, especially in usually vulnerable low spots.", - "Major beach erosion with heavy surf breaching dunes. Strong and numerous rip currents.", - "Moderate damage to marinas, docks, boardwalks, and piers. Several small craft broken away from moorings, especially in unprotected anchorages.", - ], - "Elevated": ["If realized, minor to moderate storm surge flooding can cause localized inundation mainly along immediate shorelines and in low-lying spots, or in areas farther inland near where higher surge waters move ashore.", - "Sections of near-shore roads and parking lots become overspread with surge water. Driving conditions dangerous in places where surge water covers the road.", - "Moderate beach erosion. Heavy surf also breaching dunes, mainly in usually vulnerable locations. Strong rip currents.", - "Minor to locally moderate damage to marinas, docks, boardwalks, and piers. A few small craft broken away from moorings.", - ], - "None": ["Little to no potential impacts from storm surge.", - ] - } } def _potentialImpactsSummary(self, segmentDict, productSegmentGroup, productSegment): @@ -2039,25 +1997,6 @@ class FloodingRainSection(SectionCommon): ], "recovery": ["For additional information on impacts being caused by flooding rain, refer to the local hazardous weather outlook or hurricane local statement.", ], - "default": {"Extreme": ["If realized, extreme rainfall flooding may prompt numerous evacuations and rescues.", - "Rivers and tributaries may overwhelmingly overflow their banks in many places with deep moving water. Small streams, creeks, canals, arroyos, and ditches may become raging rivers. In mountain areas, deadly runoff may rage down valleys while increasing susceptibility to rockslides and mudslides. Flood control systems and barriers may become stressed.", - "Flood waters can enter numerous structures within multiple communities, some structures becoming uninhabitable or washed away. Numerous places where flood waters may cover escape routes. Streets and parking lots become rivers of raging water with underpasses submerged. Driving conditions become very dangerous. Numerous road and bridge closures with some weakened or washed out.", - ], - "High": ["If realized, major rainfall flooding may prompt many evacuations and rescues.", - "Rivers and tributaries may rapidly overflow their banks in multiple places. Small streams, creeks, canals, arroyos, and ditches may become dangerous rivers. In mountain areas, destructive runoff may run quickly down valleys while increasing susceptibility to rockslides and mudslides. Flood control systems and barriers may become stressed.", - "Flood waters can enter many structures within multiple communities, some structures becoming uninhabitable or washed away. Many places where flood waters may cover escape routes. Streets and parking lots become rivers of moving water with underpasses submerged. Driving conditions become dangerous. Many road and bridge closures with some weakened or washed out.", - ], - "Mod": ["If realized, moderate rainfall flooding may prompt several evacuations and rescues.", - "Rivers and tributaries may quickly become swollen with swifter currents and overspill their banks in a few places, especially in usually vulnerable spots. Small streams, creeks, canals, arroyos, and ditches overflow.", - "Flood waters can enter some structures or weaken foundations. Several places may experience expanded areas of rapid inundation at underpasses, low-lying spots, and poor drainage areas. Some streets and parking lots take on moving water as storm drains and retention ponds overflow. Driving conditions become hazardous. Some road and bridge closures.", - ], - "Elevated": ["If realized, localized rainfall flooding may prompt a few evacuations.", - "Rivers and tributaries may quickly rise with swifter currents. Small streams, creeks, canals, arroyos, and ditches may become swollen and overflow in spots.", - "Flood waters can enter a few structures, especially in usually vulnerable spots. A few places where rapid ponding of water occurs at underpasses, low-lying spots, and poor drainage areas. Several storm drains and retention ponds become near-full and begin to overflow. Some brief road and bridge closures.", - ], - "None": ["Little to no potential impacts from flooding rain.", - ] - } } class TornadoSection(SectionCommon): @@ -2159,25 +2098,6 @@ class TornadoSection(SectionCommon): ], "recovery": ["For additional information on impacts being caused by tropical tornadoes, refer to the local hazardous weather outlook or hurricane local statement.", ], - "default": {"Extreme": ["The occurrence of an outbreak of tornadoes can greatly hinder the execution of other emergency activities during tropical events.", - "If realized, many places may experience tornado damage, with several spots of immense destruction, power loss, and communications failures.", - "Locations could realize sturdy buildings demolished, structures upon weak foundations swept away, mobile homes obliterated, large trees twisted and snapped with some debarked, vehicles lifted off the ground and thrown with distance, and small boats destroyed. Large and deadly projectiles can add considerably to the toll.", - ], - "High": ["The occurrence of numerous tornadoes can greatly hinder the execution of other emergency activities during tropical events.", - "If realized, many places may experience tornado damage with a few spots of immense destruction, power loss, and communications failures.", - "Locations could realize roof and wall failures of sturdy buildings with some being leveled, structures upon weak foundations blown away, mobile homes obliterated, large trees twisted and snapped with forested trees uprooted, vehicles lifted off the ground and thrown, and small boats destroyed. Large and deadly projectiles can add to the toll.", - ], - "Mod": ["The occurrence of scattered tornadoes can hinder the execution of other emergency activities during tropical events.", - "If realized, several places may experience tornado damage with a few spots of considerable damage, power loss, and communications failures.", - "Locations could realize roofs torn off frame houses, mobile homes demolished, boxcars overturned, large trees snapped or uprooted, vehicles tumbled, and small boats tossed about. Dangerous projectiles can add to the toll.", - ], - "Elevated": ["The occurrence of isolated tornadoes can hinder the execution of other emergency activities during tropical events.", - "If realized, a few places may experience tornado damage, along with power and communications disruptions.", - "Locations could realize roofs peeled off buildings, chimneys toppled, mobile homes pushed off foundations or overturned, large tree tops and branches snapped off, shallow-rooted trees knocked over, moving vehicles blown off roads, and small boats pulled from moorings.", - ], - "None": ["Little to no potential impacts from tropical tornadoes.", - ] - } } @@ -2751,7 +2671,7 @@ class StormSurgeSectionStats(SectionCommonStats): (str(phishStartTime), str(phishEndTime)), 1) if curPhish is not None and possibleStop != 2: - if curPhish >= 1: + if curPhish >= 0.5: if phishStartTime is None: phishStartTime = tr.startTime() possibleStop = 0