Merge remote-tracking branch 'vlab/tcv_16.1.2' into master_16.1.2

Former-commit-id: 77fef70f5b79331f3c57cb580f0204acc1d9b64d
This commit is contained in:
Shawn.Hooper 2016-02-16 11:10:37 -05:00
commit 6070484233
3 changed files with 106 additions and 35 deletions

View file

@ -3,7 +3,7 @@
# support, and with no warranty, express or implied, as to its usefulness for # support, and with no warranty, express or implied, as to its usefulness for
# any purpose. # any purpose.
# #
# CoastalThreat # StormSurgeThreat
# #
# Author: Tom LeFebvre/Pablo Santos # Author: Tom LeFebvre/Pablo Santos
# April 20, 2012 - To use gridded MSL TO NAVD and MSL to MLLW # April 20, 2012 - To use gridded MSL TO NAVD and MSL to MLLW
@ -19,13 +19,13 @@
# 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 # Available on time. Left inactive (commented out) for the moment until that can be fully tested later
# in 2014 or in 2015. # in 2014 or in 2015.
# May 22, 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: LeFebvre/Santos, July 27, 2015: Expanded Manual options to include Replace and Add options. # Last Modified: LeFebvre/Santos, July 27, 2015: Expanded Manual options to include Replace and Add options.
# This allows sites to specify manually different threat levels across different edit areas and time ranges. # This allows sites to specify manually different threat levels across different edit areas and time ranges.
# See 2015HTIUserGuide for details. # See 2015HTIUserGuide for details.
# #
# Feb 11, 2016 LeFebvre (16.1.2): Added code to create zero grids and manual grids when
# PSURGE not available. Added checks for current guidance for PHISH and ISC options.
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# The MenuItems list defines the GFE menu item(s) under which the # The MenuItems list defines the GFE menu item(s) under which the
# Procedure is to appear. # Procedure is to appear.
@ -185,11 +185,15 @@ class Procedure (SmartScript.SmartScript):
weName = "Surge" + pctStr + "Pctincr" weName = "Surge" + pctStr + "Pctincr"
#print "Attempting to retrieve: ", weName, level #print "Attempting to retrieve: ", weName, level
trList = self.getWEInventory(dbName, weName, level) # get the StormSurgeProb inventory
surgeTRList = self.getWEInventory(dbName, weName, level)
if len(surgeTRList) == 0:
self.statusBarMsg("No PHISH grid found.", "U")
return
if len(trList) == 0: # Make timeRanges for all 13 grids. Start with the beginning of the first Phish grid
self.statusBarMsg("No grids available for model:" + dbName, "S") baseTime = int(surgeTRList[0].startTime().unixTime() / (6 * 3600)) * (6 * 3600) #snap to 6 hour period
return None trList = self.makeTimingTRs(baseTime)
n = 1 n = 1
for tr in trList: for tr in trList:
@ -203,7 +207,13 @@ class Procedure (SmartScript.SmartScript):
end = tr.startTime().unixTime() end = tr.startTime().unixTime()
tr6 = TimeRange.TimeRange(AbsTime.AbsTime(start), tr6 = TimeRange.TimeRange(AbsTime.AbsTime(start),
AbsTime.AbsTime(end)) AbsTime.AbsTime(end))
phishGrid = self.getGrids(dbName, weName, level, tr)
surgeTR = TimeRange.TimeRange(tr.startTime(), AbsTime.AbsTime(tr.startTime().unixTime() + 3600))
if surgeTR in surgeTRList:
phishGrid = self.getGrids(dbName, weName, level, surgeTR)
else:
phishGrid = np.zeros(self.getGridShape(), 'f')
# #
# For consistency we need to add smoothing here too as we do in execute. # For consistency we need to add smoothing here too as we do in execute.
# #
@ -214,7 +224,7 @@ class Procedure (SmartScript.SmartScript):
if smoothThreatGrid is "Yes": if smoothThreatGrid is "Yes":
phishGrid = np.where(np.greater(phishGrid, 0.0), self.smoothGrid(phishGrid,3), phishGrid) phishGrid = np.where(np.greater(phishGrid, 0.0), self.smoothGrid(phishGrid,3), phishGrid)
grid = np.where(phishGrid>-100,phishGrid*3.28, -80.0) grid = np.where(phishGrid>-100, phishGrid*3.28, -80.0) # Convert units from meters to feet
self.createGrid(mutableID, "InundationTiming", "SCALAR", grid, tr6, precision=1) self.createGrid(mutableID, "InundationTiming", "SCALAR", grid, tr6, precision=1)
return return
@ -610,7 +620,7 @@ class Procedure (SmartScript.SmartScript):
print "Timing grid not found at:", trList[i] print "Timing grid not found at:", trList[i]
if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour: if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour:
timingGrids[i][modifyMask] = inundationHeight # populate where needed timingGrids[i][modifyMask] = inundationHeight # populate only where needed
self.createGrid(mutableID, "InundationTiming", "SCALAR", timingGrids[i], trList[i]) self.createGrid(mutableID, "InundationTiming", "SCALAR", timingGrids[i], trList[i])

View file

@ -1,4 +1,4 @@
# Version 2016.01.26-0 # Version 2016.02.09-0
import GenericHazards import GenericHazards
import string, time, os, re, types, copy, LogStream, collections import string, time, os, re, types, copy, LogStream, collections
@ -2096,7 +2096,7 @@ class TextProduct(HLSTCV_Common.TextProduct):
for label, latLon in refList: for label, latLon in refList:
lat, lon = latLon lat, lon = latLon
localRef = self._calcReference(lat0, lon0, lat, lon) localRef = self._calcReference(lat0, lon0, lat, lon)
localRef = localRef + " OF " + label localRef = localRef + " of " + label
localRef = localRef.replace(",","") localRef = localRef.replace(",","")
localRefs.append(localRef) localRefs.append(localRef)
return localRefs return localRefs

View file

@ -1,4 +1,4 @@
# Version 2016.01.26-0 # Version 2016.02.09-0
import GenericHazards import GenericHazards
import JsonSupport import JsonSupport
@ -513,14 +513,14 @@ class TextProduct(HLSTCV_Common.TextProduct):
gridChecks += [(self._isCorrectNumGrids, "WindThreat", 1, argDict), gridChecks += [(self._isCorrectNumGrids, "WindThreat", 1, argDict),
(self._isContinuousDuration, "Wind", 120, argDict), (self._isContinuousDuration, "Wind", 120, argDict),
(self._isContinuousDuration, "WindGust", 120, argDict), (self._isContinuousDuration, "WindGust", 120, argDict),
(self._isContinuousDuration, "pws34int", 120, argDict), (self._isContinuousDuration, "pws34int", 114, argDict),
(self._isContinuousDuration, "pws64int", 120, argDict), (self._isContinuousDuration, "pws64int", 114, argDict),
(self._isCombinedContinuousDuration, "pwsD34", "pwsN34", 96, argDict), (self._isCombinedContinuousDuration, "pwsD34", "pwsN34", 102, argDict),
(self._isCombinedContinuousDuration, "pwsD64", "pwsN64", 96, argDict),] (self._isCombinedContinuousDuration, "pwsD64", "pwsN64", 102, argDict),]
if self._PopulateSurge and len(self._coastalAreas()) != 0: if self._PopulateSurge and len(self._coastalAreas()) != 0:
gridChecks += [(self._isCorrectNumGrids, "InundationMax", 1, argDict), gridChecks += [(self._isCorrectNumGrids, "InundationMax", 1, argDict),
(self._isCorrectNumGrids, "InundationTiming", 13, argDict),] (self._isCorrectNumGrids, "InundationTiming", 12, argDict),]
missingGridErrors = [] missingGridErrors = []
for gridCheck in gridChecks: for gridCheck in gridChecks:
@ -530,9 +530,9 @@ class TextProduct(HLSTCV_Common.TextProduct):
error = "" error = ""
if gridCheck[0] == self._isCorrectNumGrids: if gridCheck[0] == self._isCorrectNumGrids:
if gridCheck[2] == 1: if gridCheck[2] == 1:
error = "%s needs exactly 1 grid" % (gridCheck[1]) error = "%s needs at least 1 grid" % (gridCheck[1])
else: else:
error = "%s needs exactly %s grids" % (gridCheck[1], gridCheck[2]) error = "%s needs at least %s grids" % (gridCheck[1], gridCheck[2])
elif gridCheck[0] == self._isContinuousDuration: elif gridCheck[0] == self._isContinuousDuration:
error = "%s needs at least %s continuous hours worth of data" % (gridCheck[1], gridCheck[2]) error = "%s needs at least %s continuous hours worth of data" % (gridCheck[1], gridCheck[2])
else: else:
@ -575,9 +575,9 @@ class TextProduct(HLSTCV_Common.TextProduct):
else: else:
gridTimes.append(gridTime) gridTimes.append(gridTime)
self.debug_print("Length of grid times: %s" % (self._pp.pformat(len(gridTimes))), 1) self.debug_print("Actual number of grids: %s" % (self._pp.pformat(len(gridTimes))), 1)
return len(gridTimes) == expectedNumGrids return len(gridTimes) >= expectedNumGrids
def _isContinuousDuration(self, weatherElement, minimumNumHours, argDict): def _isContinuousDuration(self, weatherElement, minimumNumHours, argDict):
return self._checkContinuousDuration([weatherElement], minimumNumHours, argDict) return self._checkContinuousDuration([weatherElement], minimumNumHours, argDict)
@ -1096,8 +1096,10 @@ class TextProduct(HLSTCV_Common.TextProduct):
self._currentAdvisory['ZoneData'][segment] = { self._currentAdvisory['ZoneData'][segment] = {
"WindThreat": None, "WindThreat": None,
"WindForecast": None, "WindForecast": None,
"WindHighestPhaseReached": None,
"StormSurgeThreat": None, "StormSurgeThreat": None,
"StormSurgeForecast": None, "StormSurgeForecast": None,
"StormSurgeHighestPhaseReached": None,
"FloodingRainThreat": None, "FloodingRainThreat": None,
"FloodingRainForecast": None, "FloodingRainForecast": None,
"TornadoThreat": None, "TornadoThreat": None,
@ -1328,6 +1330,11 @@ class SectionCommon():
def _isThreatNoneForEntireStorm(self, threatName): def _isThreatNoneForEntireStorm(self, threatName):
previousAdvisories = self._textProduct._getPreviousAdvisories() previousAdvisories = self._textProduct._getPreviousAdvisories()
# For the first advisory, this needs to be false otherwise
# potential impacts could be wrong
if len(previousAdvisories) == 0:
return False
for advisory in previousAdvisories: for advisory in previousAdvisories:
if advisory["ZoneData"][self._segment][threatName] != "None": if advisory["ZoneData"][self._segment][threatName] != "None":
return False return False
@ -1514,6 +1521,9 @@ class SectionCommon():
if tr == "default": if tr == "default":
records = self._textProduct._getVtecRecords(self._segment) records = self._textProduct._getVtecRecords(self._segment)
for record in records: for record in records:
if self._textProduct._currentAdvisory['ZoneData'][self._segment]["WindThreat"] != "None":
tr = "hunker down"
break
if record["phen"] in ["HU", "TR"] and record["sig"] == "W": if record["phen"] in ["HU", "TR"] and record["sig"] == "W":
if record["act"] == "CAN": if record["act"] == "CAN":
tr = "recovery" tr = "recovery"
@ -1531,6 +1541,30 @@ class SectionCommon():
self._pastWindHazardWasCAN(): self._pastWindHazardWasCAN():
tr = "recovery" tr = "recovery"
# ---------------------------------------------------------------------
# Don't allow the event to regress to an earlier phase for this section
# "default" isn't ordered because it can occur at multiple points before the recovery phase
phaseOrder = [None, "check plans", "complete preparations", "hunker down", "recovery"]
if self._sectionHeaderName == "Storm Surge":
highestPhaseReachedField = "StormSurgeHighestPhaseReached"
else: # Flooding Rain and Tornado are tied to Wind so that's why they use Wind's phase
highestPhaseReachedField = "WindHighestPhaseReached"
if tr == "default":
if self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField] == "recovery":
tr = "recovery"
else:
highestPhaseIndex = \
phaseOrder.index(self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField])
currentPhaseIndex = phaseOrder.index(tr)
if currentPhaseIndex < highestPhaseIndex:
tr = self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField]
elif currentPhaseIndex > highestPhaseIndex:
self._textProduct._currentAdvisory['ZoneData'][self._segment][highestPhaseReachedField] = tr
return tr return tr
def _pastWindHazardWasCAN(self): def _pastWindHazardWasCAN(self):
@ -2840,6 +2874,7 @@ class StormSurgeSectionStats(SectionCommonStats):
self._setStats(intersectStatList, timeRangeList) self._setStats(intersectStatList, timeRangeList)
def _setStats(self, statList, timeRangeList): def _setStats(self, statList, timeRangeList):
windows = []
phishStartTime = None phishStartTime = None
phishEndTime = None phishEndTime = None
@ -2924,13 +2959,39 @@ class StormSurgeSectionStats(SectionCommonStats):
phishStartTime = tr.startTime() phishStartTime = tr.startTime()
elif endCondition and (phishStartTime is not None) and (phishEndTime is None): elif endCondition and (phishStartTime is not None) and (phishEndTime is None):
phishEndTime = tr.startTime() phishEndTime = tr.startTime()
self._textProduct.debug_print("final phishStartTime = %s final phishEndTime = %s" %
# We found a new window, save it, reset and look for any additional windows
self._textProduct.debug_print("Found a new window:", 1)
self._textProduct.debug_print("window phishStartTime = %s window phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1) (str(phishStartTime), str(phishEndTime)), 1)
break
windows.append((phishStartTime, phishEndTime))
phishStartTime = None
phishEndTime = None
self._textProduct.debug_print("Looking for additional windows", 1)
self._textProduct.debug_print("new phishStartTime = %s new phishEndTime = %s" % self._textProduct.debug_print("new phishStartTime = %s new phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1) (str(phishStartTime), str(phishEndTime)), 1)
# Check for the case where a window doesn't end
if (phishStartTime is not None) and (phishEndTime is None):
self._textProduct.debug_print("Found a never-ending window:", 1)
self._textProduct.debug_print("window phishStartTime = %s window phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
windows.append((phishStartTime, None))
# Create the final window
if len(windows) == 0:
phishStartTime = None
phishEndTime = None
else:
phishStartTime = windows[0][0] # Start time of first window
phishEndTime = windows[-1][1] # End time of last window
self._textProduct.debug_print("Constructed the final window:", 1)
self._textProduct.debug_print("final phishStartTime = %s final phishEndTime = %s" %
(str(phishStartTime), str(phishEndTime)), 1)
self._windowSurge = "Window of concern: " self._windowSurge = "Window of concern: "