awips2/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/CreateProposedSS.py
2017-04-21 18:33:55 -06:00

841 lines
33 KiB
Python

# ----------------------------------------------------------------------------
# This software is in the public domain, furnished "as is", without technical
# support, and with no warranty, express or implied, as to its usefulness for
# any purpose.
#
# CreateProposedSS - Version 4.0
#
# Author: Lefebvre/Belk/Hardin/Santos/Trogdon
#
# ----------------------------------------------------------------------------
#
# SOFTWARE HISTORY
#
# Date Ticket# Engineer Description
# ------------- -------- --------- --------------------------------------------
# Jun 04, 2014 incorporate Inundation Grid and Incremental Grid
# Apr 12, 2016 cleanup code and refactor to use GridManipulation
# and TropicalUtility
# Jul 14, 2016 Fixed Smoothing, Added Manual Options,
# refactored code a little bit.
# Sep 19, 2016 19293 randerso Initial baseline check in
#
# Nov 13-18 2016 - Further tweaks made during SWIT testing
# Dec 15, 2016 - Added UpdateInunMax option
# Dec 21, 2016 - Deleted saveElements line in main execute
#
########################################################################
# The MenuItems list defines the GFE menu item(s) under which the
# Procedure is to appear.
# Possible items are: Populate, Edit, Consistency, Verify, Hazards
MenuItems = ["None"]
import sys, time, re, os
import AbsTime
import ProcessVariableList
import TimeRange
import TropicalUtility
import numpy as np
class Procedure (TropicalUtility.TropicalUtility):
def __init__(self, dbss):
TropicalUtility.TropicalUtility.__init__(self, dbss)
def trimTimeRange(self, weName, timeRange):
# Get a list of all grids we have for this parameter
trList = self.GM_getWEInventory(weName)
if len(trList) == 0: # nothing more to do
return
# Fragment all grids to their smallest time range
self.splitCmd([weName], timeRange)
# If there is more than 1 grid to deal with
if trList > 1:
# Make a time range from the start of the first grid, to the start
# of the desired time range
tr = self.GM_makeTimeRange(trList[0].startTime().unixTime(),
timeRange.startTime().unixTime())
# Delete all grids in this interim time range
self.deleteCmd([weName], tr)
# Get the parameter values from the last time range in the list
tr = trList[-1]
grid = self.getGrids("Fcst", weName, "SFC", tr)
# Make a new grid with these values, using the desired time range
self.createGrid("Fcst", weName, "DISCRETE", grid, timeRange)
def getTPCSurgeProbModelTime(self, modelSource, pctStr, level):
siteID = self.getSiteID()
if modelSource == "PETSS":
dbName = siteID + "_D2D_" + modelSource
else:
dbName = siteID + "_D2D_TPCSurgeProb" + modelSource
weName = "Surge" + pctStr + "Pct"
trList = self.GM_getWEInventory(weName, dbName, level)
if len(trList) == 0:
msgStr = dbName + " " + weName + " " + level + " does not exist in the TPCSurge model. "
self.statusBarMsg(msgStr, "S")
return None
modelStart = trList[0].startTime()
return modelStart
def getExceedanceHeight(self, modelSource, pctStr, level):
siteID = self.getSiteID()
if modelSource == "PETSS":
dbName = siteID + "_D2D_" + modelSource
else:
dbName = siteID + "_D2D_TPCSurgeProb" + modelSource
weName = "Surge" + pctStr + "Pct"
trList = self.GM_getWEInventory(weName, dbName, level)
print "getExceedanceHeight.....TRList for ", dbName, weName, pctStr, level
# Return None if no grids were found. This should post an error to the user.
if len(trList) == 0:
return None
modelStart = self.getTPCSurgeProbModelTime(modelSource, pctStr, level)
# Didn't find grid in the Fcst database so fetch it from model database
grid = self.getGrids(dbName, weName, level, trList[-1])
mask = grid <= -10.0 # invalid point - in meters
grid /= 0.3048 # convert meters to feet
grid[mask] = -80.0 # reset values less than -10.0 meters to -80.0 feet
if level == "SFC":
return grid, modelStart
else:
return grid
# Create InundationTiming grids from PHISH
def makeTimingGridsFromModel(self, modelSource, pctStr, level, ssea, MHHWMask):
siteID = self.getSiteID()
if modelSource == "PETSS":
dbName = siteID + "_D2D_" + modelSource
else:
dbName = siteID + "_D2D_TPCSurgeProb" + modelSource
weName = "Surge" + pctStr + "Pctincr"
trList = self.GM_getWEInventory(weName, dbName, level)
print "makeTimingGridsFromModel.....TRList for ", dbName, weName, pctStr, level
if len(trList) == 0:
self.statusBarMsg("No grids available for model:" + dbName, "S")
return
# make timeRanges based on the current time not the time of the model
timingTRList = self.makeTimingTRs(self.baseGuidanceTime())
gridList = []
for tr in trList:
start = tr.startTime().unixTime() - 6 * 3600
end = tr.startTime().unixTime()
tr6 = TimeRange.TimeRange(AbsTime.AbsTime(start),
AbsTime.AbsTime(end))
phishGrid = self.getGrids(dbName, weName, level, tr)
if phishGrid is None:
self.statusBarMsg("No PHISH grid available for:" + repr(tr), "S")
continue
phishMask = phishGrid > -25.0
phishGrid[phishMask] /= 0.3048 # convert meters to feet
phishGrid[~phishMask] = -80.0
phishMask = (phishGrid > 0.0) & ssea
phishGrid[phishMask] = self.GM_smoothGrid(phishGrid, 3, phishMask)[phishMask]
phishGrid = np.clip(phishGrid, 0.0, 100.0)
phishGrid[~ssea] = 0.0
phishGrid[MHHWMask] = 0.0
gridList.append(phishGrid)
for i, grid in enumerate(gridList):
self.createGrid("Fcst", "InundationTiming", "SCALAR", grid, timingTRList[i], precision=1)
def makeInundationMaxGrid(self, timingGrids, trList):
itCube = np.array(timingGrids)
maxGrid = np.amax(itCube, axis=0)
now = int(self._gmtime().unixTime() / 3600) * 3600
maxTimeRange = self.GM_makeTimeRange(now, now + 48 * 3600)
self.createGrid(self.mutableID(), "InundationMax", "SCALAR", maxGrid, maxTimeRange)
return maxGrid
# Fetch the VDATUM grid and mask all points below the specified value.
def getVDATUMSGrid(self, weName, threshold):
siteID = self.getSiteID()
dbName = siteID + "_D2D_VDATUMS"
# First check to see if the grid has been stored as a temporary grid
# and return that. Purely for performance purposes
fcstTRList = self.GM_getWEInventory(weName)
if len(fcstTRList) > 0:
grid = self.getGrids("Fcst", weName, "SFC", fcstTRList[0])
return grid
trList = self.GM_getWEInventory(weName, dbName)
if len(trList) == 0:
msgStr = weName + " does not exist in the VDATUMS model. "
self.statusBarMsg(msgStr, "S")
# TODO: Should we return here or throw an exception since there's no grid to operate on?
# TODO: why are we looping over all the time ranges retrieving grid
# we're not using. We should just use the last tr in the list.
# There's probably only one anyway.
for tr in trList:
grid = self.getGrids(dbName, weName, "SFC", tr, mode="First")
mask = grid <= threshold # points below threshold
grid /= 0.3048 # convert meters to feet
grid[mask] = -80.0 # set points to min value below threshold
return grid
# returns the combined key. Enforces the rule that keys with the
# same phen returns the one key with the highest priority sig.
def combinedKey(self, subKeys, newKey):
if newKey is None:
return subKeys
subKeyList = subKeys.split("^")
# check for same keys
if newKey in subKeyList:
return subKeys
defaultCombo = subKeys + "^" + newKey
# check for non-VTEC key
if "." not in newKey:
return defaultCombo
# more exceptions - these phens are above the law
exceptions = ["TO", "SV", "FF"]
sigList = ["W", "Y", "A"]
if self.keyPhen(newKey) in exceptions:
return defaultCombo
for sk in subKeyList:
if self.keyPhen(sk) == self.keyPhen(newKey):
subSig = self.keySig(sk)
newSig = self.keySig(newKey)
if subSig == newSig:
return subKeys
if subSig not in sigList or newSig not in sigList:
continue
if sigList.index(subSig) > sigList.index(newSig):
subKeys = subKeys.replace(sk, newKey)
return subKeys
return defaultCombo
# makes a new hazard given the oldKey and a new watch phen,
# sig and etn.
def makeNewKey(self, oldKey, phenSig):
# check for the dumb cases
if oldKey == "<None>" or oldKey == phenSig:
return phenSig
# split up the key, add the hazard, sort, and reassemble
parts = oldKey.split("^")
parts.append(phenSig)
parts.sort() # makes sure the same set of subKeys look the same
# assemble the new key
newKey = ""
for p in parts:
if newKey == "":
newKey = p
else:
newKey = self.combinedKey(newKey, p)
# just in case
if newKey == "":
newKey = "<None>"
return newKey
# Returns a list of unique keys for the specified grid and mask
def getUniqueKeys(self, byteGrid, keys, mask=None):
uniqueKeys = []
for keyIndex, key in enumerate(keys):
valueMask = byteGrid == keyIndex
valueMask &= mask
if valueMask.any():
uniqueKeys.append(key)
return uniqueKeys
# adds the specified hazard to weName over the specified timeRange
# and spatially over the specified mask. Combines the specified
# hazard with the existing hazards by default. For replaceMode,
# specify 0 in the combineField
def combineHazards(self, targetGrid, addHaz, mask, combine=1):
byteGrid, hazKey = targetGrid
uniqueKeys = self.getUniqueKeys(byteGrid, hazKey, mask)
for uKey in uniqueKeys:
if combine:
newKey = self.makeNewKey(uKey, addHaz)
else: # replace
newKey = addHaz
oldIndex = self.getIndex(uKey, hazKey)
newIndex = self.getIndex(newKey, hazKey)
# calculate the mask - intersection of mask and oldIndex values
editMask = (byteGrid == oldIndex) & mask
# poke in the new values
byteGrid[editMask] = newIndex
return (byteGrid, hazKey)
def addHazard(self, targetGrid, addHaz, mask, combine=1):
# Only interested in SS subKeys, so extract that part first
ssKey = ""
subKeys = self.getSubKeys(addHaz)
for subKey in subKeys:
if "SS" in subKey:
ssKey = subKey
if ssKey == "":
print "SS subKey not found in key:", addHaz
return
targetByteGrid, targetKeys = self.combineHazards(targetGrid,
ssKey, mask, combine)
return targetByteGrid, targetKeys
def deleteAllGrids(self, weList):
for weName in weList:
trList = self.GM_getWEInventory(weName)
if len(trList) == 0:
continue
start = trList[0].startTime().unixTime()
end = trList[-1].endTime().unixTime()
tr = self.GM_makeTimeRange(start, end)
self.deleteCmd([weName], tr)
return
def makeDiffGrid(self):
# Get the ProposedSS grid
trList = self.GM_getWEInventory("ProposedSS")
if len(trList) != 1:
self.statusBarMsg("No ProposedSS grids found.", "S")
return
else:
proposedTR = trList[0]
# Get the Raw guidance grid
trList = self.GM_getWEInventory("tempProposedSS")
if len(trList) != 1:
self.statusBarMsg("No tempProposedSS grids found.", "S")
return
else:
rawGuidTR = trList[0]
proposedSSGrid = self.getGrids("Fcst", "ProposedSS", "SFC", proposedTR)
rawGuidSSGrid = self.getGrids("Fcst", "tempProposedSS", "SFC", rawGuidTR)
self.calcDiffGrid(proposedSSGrid, rawGuidSSGrid, "PrevGuidDiffSS",
proposedTR)
return
def baseGuidanceTime(self):
startTime = int((self._gmtime().unixTime() - (2 * 3600)) / (6 * 3600)) * (6 * 3600)
return startTime
# 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()
trList = self.makeTimingTRs(baseTime)
gridList = []
for tr in trList:
gridList.append(self.empty(np.float32))
return trList, gridList
def execute(self, editArea):
editAreaMask = self.encodeEditArea(editArea)
# If we did not find an edit are mask
if editArea is None or (not editAreaMask.any()):
# Select the entire domain
editAreaMask = self.newGrid(True, np.bool)
# Extract the info from all storms
stormList = self.extractStormInfo()
stormNames = []
mutableID = self.mutableID()
# make a list of the active storms to pass into the variableList
for sDict in stormList:
stormNames.append(sDict["stormName"])
variableList = []
bogusStormName = "WXYZZYXW"
variableList.append(("Data Source", "N-SBN (Default)", "radio",
["N-SBN (Default)", "Backup", "PETSS", "Manual Replace", "Manual Add", "UpdateInunMax"
]))
variableList.append(("Indicate Your Situational Forecast Confidence", "Typical (Combined; 10% Exceedance)",
"radio", ["Typical (Combined; 10% Exceedance)",
"Medium (Combined; 20% Exceedance)",
"High (Combined; 30% Exceedance)",
"Higher (Combined; 40% Exceedance)",
"Highest (Combined; 50% Exceedance)"]))
variableList.append(("StormName", bogusStormName, "radio", stormNames))
variableList.append(("Hazard", "Storm Surge Watch", "radio",
["Storm Surge Watch", "Storm Surge Warning"]))
variableList.append(("Raw Guidance or Proposed SS Grid?", "ProposedSS", "radio",
["Raw Guidance", "ProposedSS"]))
variableList.append(("Inundation Threshold" , 3, "scale", [1, 8], 1))
variableList.append(("Manual Inundation settings:", "", "label"))
variableList.append(("Inundation Height" , 3, "scale", [1, 8], 1))
variableList.append(("Start Hour for Inundation Timing", 0, "scale", [0.0, 72.0], 6.0))
variableList.append(("End Hour for Inundation Timing", 6, "scale", [0.0, 78.0], 6.0))
# variableList.append(("Make Inunudation Timing Grids?", "Yes", "radio", ["Yes", "No"]))
# Display the GUI and check for cancel
varDict = {}
processVarList = ProcessVariableList.ProcessVariableList("StormSurgeWW", variableList, varDict)
status = processVarList.status()
if status.upper() != "OK":
self.cancel()
sourceOption = varDict["Data Source"]
if sourceOption == "N-SBN (Default)":
self._dataSource = "LoRes"
elif sourceOption == "Backup":
self._dataSource = "Manual"
elif sourceOption == "PETSS":
self._dataSource = "PETSS"
elif sourceOption == "Manual Replace":
self._dataSource = "LoRes"
elif sourceOption == "Manual Add":
self._dataSource = "LoRes"
# Fetch the StormSurge edit area
ssEditArea = self.getEditArea("StormSurgeWW_EditArea")
ssea = self.encodeEditArea(ssEditArea)
# Below you can configure different edit areas to specify different tide corrections
inundationThresh = varDict["Inundation Threshold"]
tempAddReplace = varDict["Raw Guidance or Proposed SS Grid?"]
# Make sure a storm was selected
stormName = varDict["StormName"]
if stormName == bogusStormName:
self.statusBarMsg("Please select a storm name.", "U")
return
# Extract storm number for selected storm
for sDict in stormList:
if sDict["stormName"] == stormName:
stormNum = int(sDict["stormNumber"])
lastModified = sDict["lastModified"]
# Make sure that the storm info has been updated within the last 7 hours
if self._gmtime().unixTime() - lastModified > 7 * 3600:
self.statusBarMsg("StormInfo for " + stormName + " is old. " + \
"Please update StormInfo first.", "U")
return
# Ensure this is a national VTEC number
if stormNum < 1000:
stormNum = int(stormNum + 1000)
confidenceStr = varDict["Indicate Your Situational Forecast Confidence"]
# extract the percent value from this string
pctPos = confidenceStr.find("%")
pctStr = confidenceStr[pctPos - 2:pctPos]
now = int(self._gmtime().unixTime() / 3600) * 3600
timeRange = self.GM_makeTimeRange(now, now + 48 * 3600)
if sourceOption in ["N-SBN (Default)", "Backup", "PETSS"]:
if stormNum is None:
self.abort("You must supply the storm!")
return
# Now get the P-surge
surgePctGrid = self.getExceedanceHeight(self._dataSource, pctStr, "FHAG0")
# Stop the tool if we didn't get the grid we wanted
if surgePctGrid is None:
self.statusBarMsg("No StormSurge guidance found for source " + self._dataSource + ".", "S")
return
surgePctGrid = np.clip(surgePctGrid, 0.0, 100.0)
surgePctGrid[~ssea] = 0.0
# Get NAVD grids
surgePctGridNAVD, modelStart = self.getExceedanceHeight(self._dataSource, pctStr, "SFC")
surgePctGridNAVD = np.clip(surgePctGridNAVD, -80.0, 100.0)
surgePctGridNAVD[~ssea] = -80.0
# smooth grids
surgePctGrid = self.GM_smoothGrid(surgePctGrid, 3, (surgePctGrid > 0.0) & ssea)
surgePctGridNAVD = self.GM_smoothGrid(surgePctGridNAVD, 3, (surgePctGridNAVD > -10.0) & ssea)
# Calculate and display surge guidance grids
msltonavd = self.getVDATUMSGrid("MSLtoNAVD88", -0.40)
navdtomllw = self.getVDATUMSGrid("NAVD88toMLLW", -2.20)
navdtomhhw = self. getVDATUMSGrid("NAVD88toMHHW", -3.40)
validSurgeMask = surgePctGridNAVD > -80.0
wTopoMask = validSurgeMask & (msltonavd > -80.0)
surgePctGridMSL = self.newGrid(-80.0)
surgePctGridMSL[wTopoMask] = (surgePctGridNAVD - msltonavd)[wTopoMask]
mllwMask = validSurgeMask & (navdtomllw > -80.0)
surgePctGridMLLW = self.newGrid(-80.0)
surgePctGridMLLW[mllwMask] = (surgePctGridNAVD + navdtomllw)[mllwMask]
mhhwMask = validSurgeMask & (navdtomhhw > -80.0)
surgePctGridMHHW = self.newGrid(-80.0)
surgePctGridMHHW[mhhwMask] = (surgePctGridNAVD + navdtomhhw)[mhhwMask]
surgePctGridMSL = np.clip(surgePctGridMSL, -30.0, 100.0)
surgePctGridMLLW = np.clip(surgePctGridMLLW, -30.0, 100.0)
surgePctGridNAVD = np.clip(surgePctGridNAVD, -30.0, 100.0)
surgePctGridMHHW = np.clip(surgePctGridMHHW, -30.0, 100.0)
# Clip the MHHW grid at 0.0
MHHWMask = surgePctGridMHHW <= 0.0
surgePctGrid[MHHWMask] = 0.0
weList = ["InundationMax", "InundationTiming", "SurgeHtPlusTideMSL", "SurgeHtPlusTideNAVD", "SurgeHtPlusTideMHHW", "SurgeHtPlusTideMLLW"]
self.deleteAllGrids(weList)
now = int(self._gmtime().unixTime() / 3600) * 3600
guidanceTR = self.GM_makeTimeRange(now, now + 48 * 3600)
self.createGrid("Fcst", "SurgeHtPlusTideMSL", "SCALAR",
surgePctGridMSL, guidanceTR, precision=2)
self.createGrid("Fcst", "SurgeHtPlusTideMLLW", "SCALAR",
surgePctGridMLLW, guidanceTR, precision=2)
self.createGrid("Fcst", "SurgeHtPlusTideNAVD", "SCALAR",
surgePctGridNAVD, guidanceTR, precision=2)
self.createGrid("Fcst", "SurgeHtPlusTideMHHW", "SCALAR",
surgePctGridMHHW, guidanceTR, precision=2)
self.createGrid("Fcst", "SurgeHtPlusTideMLLW", "SCALAR",
surgePctGridMLLW, guidanceTR, precision=2)
elif sourceOption in ["Manual Replace", "Manual Add"]:
# Figure out the total number of points
gridSize = self.getGridShape()
totalPoints = gridSize[0] * gridSize[1]
# Make sure the user selected a real edit area before continuing
selectedMask = self.encodeEditArea(editArea) # make the mask based on the selected edit area
if editArea is None or (not selectedMask.any()) or np.count_nonzero(selectedMask) == totalPoints:
self.statusBarMsg("Please select an edit area before running the Manual Replace or Manual Add option." , "S")
return
# modelStart = self.getTPCSurgeProbModelTime("LoRes", pctStr, "SFC")
inundationHeight = float(varDict["Inundation Height"])
inunStartHour = float(varDict["Start Hour for Inundation Timing"])
inunEndHour = float(varDict["End Hour for Inundation Timing"])
modifyMask = selectedMask & ssea
if inunStartHour >= inunEndHour:
self.statusBarMsg("Please define the end hour after the start hour.", "S")
return
surgePctGrid = self.empty(np.float32)
# Fetch the old grids if we're adding
if sourceOption == "Manual Add":
imTRList = self.GM_getWEInventory("InundationMax", self.mutableID(), "SFC")
if len(imTRList) > 0:
imTR = imTRList[0]
surgePctGrid = self.getGrids(mutableID, "InundationMax", "SFC", imTR)
surgePctGrid = surgePctGrid * 0 # reset the surgePctGrid
surgePctGrid[modifyMask] = inundationHeight # poke in the new values
# Make the timing grids
baseTime = self.baseGuidanceTime()
self.deleteAllGrids(["InundationMax","SurgeHtPlusTideMSL", "SurgeHtPlusTideMLLW",
"SurgeHtPlusTideNAVD", "SurgeHtPlusTideMHHW", "SurgeHtPlusTideMLLW"])
if sourceOption == "Manual Replace": # Make new grids and replace all IT grids
self.deleteAllGrids(["InundationTiming"])
trList, timingGrids = self.getTimingGrids() # fetch empty grids with times
for i, tr in enumerate(trList):
start = tr.startTime().unixTime()
end = tr.endTime().unixTime()
if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour:
timingGrids[i][selectedMask] = inundationHeight # populate only where needed
timingGrids[i][~ssea] = 0.0
for i, tr in enumerate(trList):
timingGrids[i] = np.clip(timingGrids[i], 0.0, 100.0)
self.createGrid(mutableID, "InundationTiming", "SCALAR", timingGrids[i], tr)
# Finally create the surge grid which will be saved as the InundationMax
itCube = np.array(timingGrids)
surgePctGrid = np.amax(itCube, axis = 0)
self.makeInundationMaxGrid(timingGrids, trList)
elif sourceOption == "Manual Add": # Just replace the selected grid points over the selected time
# Fetch the existing IT grids
itTRList = self.GM_getWEInventory("InundationTiming", self.mutableID(), "SFC")
if len(itTRList) == 0:
self.statusBarMsg("No InundationTiming grids found at all. Inundation grids required to exist when running with this option. Otherwise run with Manual Replace Option.", "S")
return
timingGrids = []
trList = []
# Fetch all the timing grids
for tr in itTRList:
grid = self.getGrids(mutableID, "InundationTiming", "SFC", tr)
timingGrids.append(grid)
trList.append(tr)
# Now poke in the selected value in each grid we need to modify
for i in range(len(timingGrids)):
start = trList[i].startTime().unixTime()
end = trList[i].endTime().unixTime()
if (start - baseTime) / 3600 >= inunStartHour and (end - baseTime) / 3600 <= inunEndHour:
timingGrids[i][modifyMask] = inundationHeight # poke in the values and create the grids
# Delete the grids before re-creating them
self.deleteAllGrids(["InundationTiming"])
# Create the InundationTiming grids
for i in range(len(timingGrids)):
self.createGrid(mutableID, "InundationTiming", "SCALAR", timingGrids[i], trList[i])
# Finally create the surge grid which will be saved as the InundationMax
itCube = np.array(timingGrids)
surgePctGrid = np.amax(itCube, axis = 0)
self.makeInundationMaxGrid(timingGrids, itTRList)
else: # Then this is UpdateInunMax
self.deleteAllGrids(["InundationMax","SurgeHtPlusTideMSL", "SurgeHtPlusTideMLLW",
"SurgeHtPlusTideNAVD", "SurgeHtPlusTideMHHW", "SurgeHtPlusTideMLLW"])
itTRList = self.GM_getWEInventory("InundationTiming", self.mutableID(), "SFC")
if len(itTRList) == 0:
self.statusBarMsg("No InundationTiming grids found at all. Inundation grids required to exist when running with this option. Otherwise run with Manual Replace Option.", "S")
return
timingGrids = []
# Fetch all the timing grids
for tr in itTRList:
grid = self.getGrids(self.mutableID(), "InundationTiming", "SFC", tr)
timingGrids.append(grid)
# Finally create the surge grid which will be saved as the InundationMax
try:
surgePctGrid = self.empty(np.float32)
except AttributeError:
surgePctGrid = np.zeros(self.getGridShape(), np.float32)
surgePctGrid = self.makeInundationMaxGrid(timingGrids, itTRList)
#return
# Done with manual options
# Get the hazard key based on the GUI
hazardType = varDict["Hazard"]
# Make the key with the storm number
if hazardType == "Storm Surge Watch":
ssAddKey = "SS.A:" + str(stormNum)
# ssAddKey = "SS.W:" + str(stormNum)
elif hazardType == "Storm Surge Warning":
ssAddKey = "SS.W:" + str(stormNum)
# ssAddKey = "SS.A:" + str(stormNum)
else:
ssAddKey = "<None>"
# Calculate the new pSurge mask restricting to the storm surge
# edit area and the selected edit area
pSurgeMask = surgePctGrid > inundationThresh
pSurgeMask = pSurgeMask & ssea
pSurgeMask = pSurgeMask & editAreaMask
############################# Now make the Hazard grid and check for conflicts ########################
# Make an empty grid which will be populated
ssGrid = self.empty(np.int8)
ssKeys = ["<None>", ssAddKey]
ssIndex = self.getIndex(ssAddKey, ssKeys)
ssGrid[pSurgeMask] = ssIndex
# If we're making the temp grid, just make it now with no Hazard merging and return
hazTRList = self.GM_getWEInventory("Hazards")
if tempAddReplace == "Raw Guidance":
for tr in hazTRList:
hazGrid = self.getGrids("Fcst", "Hazards", "SFC", tr)
if self.anyHazardConflictsByPoint(hazGrid, (ssGrid, ssKeys), editAreaMask):
self.statusBarMsg("ETNs do not match Hazards grid in selected area for Raw Guidance.", "U")
return
self.createGrid("Fcst", "tempProposedSS" , "DISCRETE", (ssGrid, ssKeys), timeRange)
self.makeDiffGrid()
return
proposedSSTRList = self.GM_getWEInventory("ProposedSS")
# Next we need to extract the existing SS Hazards from the Hazard grid
# and insert those hazards in the SS grid so we never lose them.
# So iterate over each Hazard grid and add SS values as we go
if len(proposedSSTRList) == 0:
hazSSGrid = self.empty(np.int8)
hazSSKeys = ["<None>"]
# A ProposedSS grid already exists - start with the last one
else:
hazSSGrid, hazSSKeys = self.getGrids("Fcst", "ProposedSS", "SFC", proposedSSTRList[-1])
# Get the grids to check for conflicts
for tr in hazTRList:
hazGrid = self.getGrids("Fcst", "Hazards", "SFC", tr)
if self.anyHazardConflictsByPoint(hazGrid, (ssGrid, ssKeys), editAreaMask):
self.statusBarMsg("ETNs do not match Hazards grid in selected area. Please Revert your grids.", "U")
return
print "No conflicts found...."
# Merge any existing SS hazards into the ProposedSS grid
if len(hazTRList) > 0:
for hazTR in hazTRList:
hazGrid, hazKeys = self.getGrids("Fcst", "Hazards", "SFC", hazTR)
# Merge the selected hazards, in this case SS.A and SS.W,
# into the existing ProposedSS grid
(hazSSGrid, hazSSKeys) = self.mergeCertainHazards(
(hazSSGrid, hazSSKeys), (hazGrid, hazKeys), hazTR,
["SS.W", "SS.A"])
# Update these hazards where there was no hazard, using the pSurge grid
noneIndex = self.getIndex("<None>", hazSSKeys)
ssIndex = self.getIndex(ssAddKey, hazSSKeys)
mask = pSurgeMask & (hazSSGrid == noneIndex)
hazSSGrid[mask] = ssIndex
# Finally upgrade Watch areas to Warnings over the edit area, if necessary
if "SS.W" in ssAddKey:
# Find Watch points over the edit area
print "Upgrading watches to warnings."
# Find the key containing "SS.A" that matches the ETN
etn = self.getETN(ssAddKey)
watchKey = "SS.A:" + etn
ssWatchIndex = self.getIndex(watchKey, hazSSKeys)
ssWarningIndex = self.getIndex(ssAddKey, hazSSKeys)
mask = (hazSSGrid == ssWatchIndex) & pSurgeMask
hazSSGrid[mask] = ssWarningIndex
# Now create the new storm surge hazard grid(s)
# Create a new time range
# start = modelStart.unixTime() - 80 * 3600
# end = start + 78 * 3600
# timeRange = TimeRange.TimeRange(AbsTime.AbsTime(start),
# AbsTime.AbsTime(end))
#***********************************************************************************
weNameList = ["ProposedSS", "InitialSS"]
now = int(self._gmtime().unixTime() / 3600) * 3600
timeRange = self.GM_makeTimeRange(now, now + 48 * 3600)
# Make an InitialSS grid if it's the first time
for weName in weNameList:
self.trimTimeRange(weName, timeRange)
self.createGrid("Fcst", weName, "DISCRETE",
(hazSSGrid, hazSSKeys), timeRange)
# Make the timing grids and the max grid from the model
if sourceOption in ["N-SBN (Default)", "Backup", "PETSS"]:
self.makeTimingGridsFromModel(self._dataSource, pctStr, "FHAG0", ssea, MHHWMask)
print "Creating new InundationMax grid..............................................."
self.createGrid("Fcst", "InundationMax", "SCALAR", surgePctGrid,
timeRange, precision=1)