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

293 lines
11 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.
#
# FinalizeHazards.py
# Version 3.0 - 15 April 2016 - Code cleanup and refactor
#
# Author: Nate Hardin, Tom LeFebvre
# ------------------------------------------------------------------------------
#
#
# SOFTWARE HISTORY
#
# Date Ticket# Engineer Description
# ------------ ---------- ----------- ------------------------------------------
# Sep 19, 2016 19293 randerso Initial baseline check in
# Mar 07, 2017 29986 randerso Fix issue with no trop wind in Hazardswfo
#
################################################################################
# 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 HazardUtils
import LogStream
import ProcessVariableList
import TimeRange
import TropicalUtility
import numpy as np
VariableList = [("Merge Storm Surge Hazards?", "No", "radio", ["Yes", "No"]), ]
class Procedure (TropicalUtility.TropicalUtility):
def __init__(self, dbss):
TropicalUtility.TropicalUtility.__init__(self, dbss)
# Extracts just wind hazards out of the ISC grids and returns a list
# of hazard grid
def makeISCWindHazardGrids(self):
tropicalWindHazList = ["TR.W", "TR.A", "HU.W", "HU.A"]
# Get a list of all times which have WFO Hazards
trList = self.GM_getWEInventory("Hazardswfo", "ISC")
hazGridList = []
hazTRList = []
# Initialize a new mask to clip Wind hazards to land-areas only
cwaMaskNoMarine = self.encodeEditArea("WFO_AllLand")
# Get the current time
currentTime = self._gmtime()
# Process all the times which have WFO Hazards
for tr in trList:
# Skip all grids which are in the past
if tr.endTime() < currentTime:
continue
# Get all the WFO Hazards for this time
wfoHazGrid = self.getGrids("ISC", "Hazardswfo", "SFC", tr)
# Get ready to construct a new Hazards grid
iscHazGrid = self.empty(np.int8)
iscHazKeys = ["<None>"]
# For each wind hazard, extract the area from the ISC grid
# and set those same points in our temporary grid.
for haz in tropicalWindHazList:
# Find all the areas in the domain where this hazard exists
keyMaskList = self.extractHazards(wfoHazGrid, haz)
# Process all areas identified to have current tropical hazard
for hazKey, hazMask in keyMaskList:
# Filter out non-tropical hazards
windHazKey = self.purifyKey(hazKey, tropicalWindHazList)
# If there is nothing left to do, move on to next hazard
if windHazKey == "":
continue
# Poke the values into the new ISC hazard grid, ignoring
# marine-based tropical wind hazards
hazMask &= cwaMaskNoMarine
iscIndex = self.getIndex(windHazKey, iscHazKeys)
iscHazGrid[hazMask] = iscIndex
# If the current grid is equal to the last grid, just update the
# endTime of the last grid
if len(iscHazKeys) > 1:
if tr != trList[0]:
if len(hazGridList) > 0:
if np.array_equal(hazGridList[-1][0], iscHazGrid):
hazTRList[-1] = TimeRange.TimeRange(
hazTRList[-1].startTime(), tr.endTime())
continue
# Save this grid, but only if it's not empty
if len(iscHazKeys) > 1:
hazTRList.append(tr)
hazGridList.append((iscHazGrid, iscHazKeys))
return hazTRList, hazGridList
# Checks for possible conflicts between existing NHC hazards and the
# WFO hazards extracted from the ISC grid. Returns the list of CWAs
# that conflict in any way with the NHC hazards.
def checkForAnyConflicts(self, cwaList, propTR):
# Make a list of all WFOs with conflicting tropical hazards
conflictingSites = []
trList = self.GM_getWEInventory("Hazardswfo", "ISC")
proposedGrid = self.getGrids("Fcst", "ProposedSS", "SFC", propTR)
# Make a dictionary containing each CWA's grid mask, so we only need
# to make it once.
cwaMasks = {}
for cwa in cwaList:
cwaMasks[cwa] = self.encodeEditArea(cwa.upper())
# Get the current time
currentTime = self._gmtime()
# Process all the available WFO Hazards
for tr in trList:
# We're only interested in future hazard grids
if tr.endTime() < currentTime:
continue
# Get all the WFO Hazards for this time
hazardGrid = self.getGrids("ISC", "Hazardswfo", "SFC", tr)
# See if there are any hazard conflicts with any WFO
for cwa in cwaList:
# If there are any tropical hazard conflicts
if self.anyHazardConflicts(hazardGrid, proposedGrid,
cwaMasks[cwa]):
# Add this WFO to the conflicting office list - if its
# not already there
if cwa not in conflictingSites:
conflictingSites.append(cwa)
return conflictingSites
def execute(self, varDict):
# Extract the wind hazards out of the WFO ISC hazard grids.
# This returns hazard-like grids to which we will add Surge hazards
hazTRList, hazGrids = self.makeISCWindHazardGrids()
propTRList = self.GM_getWEInventory("ProposedSS")
if len(hazTRList) == 0 and len(propTRList) == 0:
self.statusBarMsg("No Proposed or WFO ISC grids found. Aborting.",
"S")
return
if len(propTRList) > 1:
self.statusBarMsg("Multiple ProposedSS grids found. " +
"Please remove all but the current grid and re-run FinalizeHazards.",
"U")
return
if varDict["Merge Storm Surge Hazards?"] == "No" or len(propTRList) == 0:
# Delete all existing Hazard Grids since we're starting from scratch
self.deleteCmd(["Hazards"], TimeRange.allTimes())
for grid, tr in zip(hazGrids, hazTRList):
self.createGrid("Fcst", "Hazards", "DISCRETE", grid, tr)
# Save and publish the Hazards grids
self.saveElements(["Hazards"])
self.publishElements(["Hazards"], TimeRange.allTimes())
else:
propTR = propTRList[0]
conflictingSites = self.checkForAnyConflicts(self._surgeWfos, propTR)
# If there are any conflicting sites, report which ones and punt
if len(conflictingSites) > 0:
siteStr = " ".join(conflictingSites)
self.statusBarMsg("Conflicting hazards were found from the " +
"following sites: " + siteStr, "U")
return
#=======================================================================
# If there were not any WFO ISC hazards found, make an empty grid
# based on the ProposedSS timeRange
propGrid, propKeys = self.getGrids("Fcst", "ProposedSS", "SFC", propTR)
if len(hazTRList) == 0:
# Make empty hazard grid
hazTRList.append(propTR)
hazGrid = self.empty(np.int8)
hazKeys = ["<None>"]
hazGrids.append((hazGrid, hazKeys))
# save mask where there were SS hazards
prevHazTRList = self.GM_getWEInventory("Hazards", timeRange=propTR)
prevSSMask = self.empty(np.bool)
for tr in prevHazTRList:
hazardGrid, hazardKeys = self.getGrids("Fcst", "Hazards", "SFC", tr)
# Look for SS. hazards
for key in hazardKeys:
if "SS." in key:
hazardIndex = self.getIndex(key, hazardKeys)
prevSSMask |= (hazardGrid == hazardIndex)
# Delete all existing Hazard Grids since we're starting from scratch
self.deleteCmd(["Hazards"], TimeRange.allTimes())
# Save the new hazard grids to the database
for grid, tr in zip(hazGrids, hazTRList):
self.createGrid("Fcst", "Hazards", "DISCRETE", grid, tr)
# If we could not find a time range for the Hazards grid
if len(hazTRList) == 0:
# Use the time range from the PropossedSS grid instead
hazTRList = propTRList
# Now add ProposedSS keys back into the hazard grids
for hazTR in hazTRList:
# Only add Proposed hazards where the Hazards overlap
if not hazTR.overlaps(propTR):
continue
# Process all the keys in the PropossedSS grids
for propIndex, propKey in enumerate(propKeys):
# If this is a "<None>" key, ignore it
if "None" in propKey:
continue
# Get the area where this hazard is located, and it intersects
# with land
mask = propGrid == propIndex
# Combine surge hazard with current hazards
self._hazUtils._addHazard("Hazards", hazTR, propKey, mask,
combine=1)
# Copy new ProposedSS grid to InitialSS
proposedSS = self.getGrids("Fcst", "ProposedSS", "SFC", propTR)
self.createGrid("Fcst", "InitialSS", "DISCRETE", proposedSS, propTR)
# Get the components of each grid
propGrid, propKeys = proposedSS
# Get the index we need to find areas of no hazards
noneIndex = self.getIndex("<None>", propKeys)
# See where there are hazards (should only be SS hazards)
propSSMask = (propGrid != noneIndex)
# Mask any area that has or previously had an SS hazard
anyChanges = prevSSMask | propSSMask
# Save all the grids we modified, clean up after collaboration
self.unloadWE("Fcst", "CollabDiffSS", "SFC")
self.saveElements(["Hazards", "InitialSS", "ProposedSS"])
# Publish all the grids we will need to keep
self.publishElements(["Hazards", "InitialSS", "ProposedSS"],
TimeRange.allTimes())
# If we are not in test mode - send the final message
if not self._testMode:
self.notifyWFOs("Hazards", anyChanges)
# let forecaster know the procedure is completed
self.statusBarMsg("Procedure completed. Run CreateNatlTCVZoneGroups.", "A")