OB_14.1.1-21 baseline
Former-commit-id:29681c7ca4
[formerly1d92e5bab6
[formerly d220320ed3c6e9a0fe9fe26d83dd71eec6eafa0b]] Former-commit-id:1d92e5bab6
Former-commit-id:271ec85c0c
This commit is contained in:
parent
2613e13e08
commit
5179a4f970
6 changed files with 458 additions and 383 deletions
|
@ -1,61 +1,70 @@
|
|||
##
|
||||
# This software was developed and / or modified by Raytheon Company,
|
||||
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
#
|
||||
# U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
# pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
#
|
||||
# U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
# This software product contains export-restricted data whose
|
||||
# export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
# to non-U.S. persons whether in the United States or abroad requires
|
||||
# an export license or other authorization.
|
||||
#
|
||||
# Contractor Name: Raytheon Company
|
||||
# Contractor Address: 6825 Pine Street, Suite 340
|
||||
# Mail Stop B8
|
||||
# Omaha, NE 68106
|
||||
# 402.291.0100
|
||||
#
|
||||
# Contractor Name: Raytheon Company
|
||||
# Contractor Address: 6825 Pine Street, Suite 340
|
||||
# Mail Stop B8
|
||||
# Omaha, NE 68106
|
||||
# 402.291.0100
|
||||
#
|
||||
# See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
# further licensing information.
|
||||
##
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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.
|
||||
#
|
||||
# MergeHazards
|
||||
#
|
||||
# Author: lefebvre
|
||||
#
|
||||
# This procedure reads all of the temporary hazard grids and selectively
|
||||
# loads them in the the "Hazards" grid.
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# 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 = ["Hazards"]
|
||||
|
||||
#import Tkinter
|
||||
import SmartScript
|
||||
import string
|
||||
import HazardUtils
|
||||
import VTECTable
|
||||
import LogStream
|
||||
import numpy
|
||||
from MessageBox import MessageBox
|
||||
|
||||
from HazardUtils import MODEL
|
||||
from HazardUtils import ELEMENT
|
||||
from HazardUtils import LEVEL
|
||||
|
||||
######################### CONFIGURATION SECTION ######################
|
||||
#
|
||||
# This dictionary defines which hazards cannot be combined with other
|
||||
# Hazards. The structure lists each hazard in the VTECTable followed
|
||||
# by a list of VTEC codes that may not be combined with it at the same
|
||||
# grid point. For example "DS.W" : ["DU.Y"] means that DS.W may not
|
||||
# be combined with a DU.Y hazard at the same grid point.
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# 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.
|
||||
#
|
||||
# MergeHazards
|
||||
#
|
||||
# Author: lefebvre
|
||||
#
|
||||
# This procedure reads all of the temporary hazard grids and selectively
|
||||
# loads them in the the "Hazards" grid.
|
||||
# ----------------------------------------------------------------------------
|
||||
#
|
||||
# SOFTWARE HISTORY
|
||||
#
|
||||
# Date Ticket# Engineer Description
|
||||
# ------------ ---------- ----------- --------------------------
|
||||
# Dec 23, 2013 16893 ryu Check in njensen's change to removeTempHazards()
|
||||
# to call SmartScript.unloadWEs().
|
||||
#
|
||||
########################################################################
|
||||
|
||||
# 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 = ["Hazards"]
|
||||
|
||||
#import Tkinter
|
||||
import SmartScript
|
||||
import string
|
||||
import HazardUtils
|
||||
import VTECTable
|
||||
import LogStream
|
||||
import numpy
|
||||
from MessageBox import MessageBox
|
||||
|
||||
from HazardUtils import MODEL
|
||||
from HazardUtils import ELEMENT
|
||||
from HazardUtils import LEVEL
|
||||
|
||||
######################### CONFIGURATION SECTION ######################
|
||||
#
|
||||
# This dictionary defines which hazards cannot be combined with other
|
||||
# Hazards. The structure lists each hazard in the VTECTable followed
|
||||
# by a list of VTEC codes that may not be combined with it at the same
|
||||
# grid point. For example "DS.W" : ["DU.Y"] means that DS.W may not
|
||||
# be combined with a DU.Y hazard at the same grid point.
|
||||
|
||||
HazardsConflictDict = {
|
||||
"AF.W" : ["AF.Y"],
|
||||
"AF.Y" : ["AF.W"],
|
||||
|
@ -187,301 +196,303 @@ HazardsConflictDict = {
|
|||
"ZR.Y" : ["BZ.A", "LE.A", "WS.A", "BZ.W", "IS.W", "WS.W", "LE.W",
|
||||
"WW.Y", "LE.Y"],
|
||||
}
|
||||
|
||||
########################## END OF CONFIGURATION SECTION ########################
|
||||
|
||||
class Procedure(SmartScript.SmartScript):
|
||||
def __init__(self, dbss):
|
||||
SmartScript.SmartScript.__init__(self, dbss)
|
||||
self._dbss = dbss
|
||||
|
||||
##
|
||||
# Get the list of loaded temporary hazard parms
|
||||
# @return: Temporary hazard parm names, i.e., ["hazAFY"]
|
||||
# @rtype: List of Strings
|
||||
def getHazardParmNames(self):
|
||||
parms = self.loadedParms()
|
||||
hazParms = []
|
||||
for weName, level, dbID in parms:
|
||||
if string.find(weName, "haz") == 0:
|
||||
# TODO: Why is this back/forth xform needed?
|
||||
key = self._hazUtils._tempWENameToKey(weName)
|
||||
index = string.find(key, ":")
|
||||
if index != -1:
|
||||
mkey = key[0:index]
|
||||
segNum = key[index+1:]
|
||||
else:
|
||||
mkey = key
|
||||
segNum = ""
|
||||
|
||||
# append the hazard and a description
|
||||
parmName = "haz" + key
|
||||
parmName = string.replace(parmName, ".", "")
|
||||
parmName = string.replace(parmName, ":", "")
|
||||
hazParms.append(parmName)
|
||||
|
||||
return hazParms
|
||||
|
||||
##
|
||||
# Unload (delete) all the temporary hazards
|
||||
def removeTempHazards(self):
|
||||
parms = self.loadedParms()
|
||||
|
||||
for weName, level, dbID in parms:
|
||||
if string.find(weName, "haz") == 0:
|
||||
self.unloadWE(MODEL, weName, level)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# The action performed when the user opts to cancel a merge.
|
||||
# This was a callback under Tcl/tk; now displayDialog invokes
|
||||
# it directly.
|
||||
def cancelCommand(self):
|
||||
LogStream.logEvent("MergeHazards: cancel")
|
||||
return
|
||||
|
||||
##
|
||||
# The action performed when the user opts to continue a merge.
|
||||
# This was a callback under Tcl/tk; now displayDialog invokes
|
||||
# it directly.
|
||||
def continueCommand(self):
|
||||
LogStream.logEvent("MergeHazards: continue")
|
||||
parm = self.getParm(MODEL, ELEMENT, LEVEL)
|
||||
parm.setMutable(True)
|
||||
self.mergeHazardGrids()
|
||||
return
|
||||
|
||||
##
|
||||
# Displays a dialog box and queries the user to continue to merge or
|
||||
# abort the merge
|
||||
def displayDialog(self, message):
|
||||
messageBox = MessageBox(style=MessageBox.ICON_WARNING)
|
||||
messageBox.setText("MakeHazard")
|
||||
messageBox.setMessage(message)
|
||||
messageBox.setButtonLabels(["Continue Merge", "Cancel Merge"])
|
||||
messageBox.setDefaultIndex(1)
|
||||
if (messageBox.open() == 0):
|
||||
self.continueCommand()
|
||||
else:
|
||||
self.cancelCommand()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Returns the set of hazParms grids that overlap with the specified
|
||||
# timeRange.
|
||||
# @param hazParms: Hazard parm names to check
|
||||
# @type hazParms: Sequence of string
|
||||
# @param timeRange: The time range to check for overlap with
|
||||
# @type timeRange: Python TimeRange
|
||||
# @return: Byte grids and keys of the overlapping parms
|
||||
# @rtype: 2-tuple: list of byte arrays, list of list of strings
|
||||
def getOverlappingHazGrids(self, hazParms, timeRange):
|
||||
byteGridList = []
|
||||
keyList = []
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
for tr in trList:
|
||||
if tr.overlaps(timeRange):
|
||||
byteGrid, hazKey = self.getGrids(MODEL, hazParm, LEVEL,
|
||||
tr, mode="First")
|
||||
if isinstance(hazKey, str):
|
||||
hazKey = eval(hazKey)
|
||||
byteGridList.append(byteGrid)
|
||||
keyList.append(hazKey)
|
||||
|
||||
return byteGridList, keyList
|
||||
|
||||
##
|
||||
# Returns the first non-None key it finds in the keyList
|
||||
# @param keyList: Keys to search
|
||||
# @type keyList: Sequence of string
|
||||
# @return: First key that is not "<None>"
|
||||
# @rtype: string
|
||||
def getHazardKey(self, keyList):
|
||||
for k in keyList:
|
||||
if k != "<None>":
|
||||
return k
|
||||
|
||||
##
|
||||
# Checks the specified hazard grids to see if they are conflicting
|
||||
# Each grid is a tuple (byteGrid, key). Uses the configurable
|
||||
# HazardConflictDict to determine whether two hazards can be combined
|
||||
# at the same grid point. Returns an empty list if no conflict or
|
||||
# the list of hazards if they do.
|
||||
#
|
||||
# This method should really only be used internally; it assumes that
|
||||
# there is at most one key other than "<None>", and that it contains
|
||||
# a single subkey.
|
||||
#
|
||||
# @param hazGrid1: The first hazard grid
|
||||
# @type hazGrid1: 2-tuple: numpy array of int8, list of String
|
||||
# @param hazGrid2: The second hazard grid
|
||||
# @type hazGrid2: 2-tuple: numpy array of int8, list of String
|
||||
# @return: conflicting hazard names or empty list
|
||||
# @rtype: list
|
||||
def conflictingHazards(self, hazGrid1, hazGrid2):
|
||||
byteGrid1, hazKey1 = hazGrid1
|
||||
byteGrid2, hazKey2 = hazGrid2
|
||||
|
||||
key1 = self.getHazardKey(hazKey1)
|
||||
key2 = self.getHazardKey(hazKey2)
|
||||
phenSig1 = key1[0:4] # remove the etn
|
||||
phenSig2 = key2[0:4]
|
||||
|
||||
keyConflict = False
|
||||
if phenSig1 == phenSig2 and key1 != key2:
|
||||
keyConflict = True
|
||||
elif HazardsConflictDict.has_key(phenSig1):
|
||||
if phenSig2 in HazardsConflictDict[phenSig1]:
|
||||
keyConflict = True
|
||||
|
||||
if keyConflict:
|
||||
# calculate the overlap, adding the grids together will tell us if
|
||||
# there is any overlap. Any grid points > 1 are overlapped
|
||||
totalGrid = byteGrid1 + byteGrid2
|
||||
overlapMask = numpy.greater(totalGrid, 1)
|
||||
if numpy.any(overlapMask):
|
||||
return [key1, key2]
|
||||
|
||||
return []
|
||||
|
||||
##
|
||||
# See if there are any temporary hazards for the same position and time
|
||||
# that conflict with one another.
|
||||
#
|
||||
# @param hazParms: Temporary hazard parm names to check.
|
||||
# @type hazParms: sequence of string
|
||||
# @return: The first conflict, or None if there are no conflicts
|
||||
# @rtype: 2-tuple(TimeRange, list of string) or NoneType
|
||||
def checkForHazardConflicts(self, hazParms):
|
||||
timeList = []
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
for tr in trList:
|
||||
if tr.startTime().unixTime() not in timeList:
|
||||
timeList.append(tr.startTime().unixTime())
|
||||
if tr.endTime().unixTime() not in timeList:
|
||||
timeList.append(tr.endTime().unixTime())
|
||||
|
||||
timeList.sort() # sort the list
|
||||
|
||||
for t in xrange(len(timeList) - 1):
|
||||
start = timeList[t]
|
||||
end = timeList[t+1]
|
||||
timeRange = self._hazUtils._makeTimeRange(start, end)
|
||||
byteGridList = []
|
||||
keyList = []
|
||||
byteGridList, keyList = self.getOverlappingHazGrids(hazParms, timeRange)
|
||||
# compare each grid to all other grids at this timeRange
|
||||
for firstIndex in xrange(len(byteGridList) - 1):
|
||||
for secondIndex in xrange(firstIndex + 1, len(byteGridList)):
|
||||
grid1 = (byteGridList[firstIndex], keyList[firstIndex])
|
||||
grid2 = (byteGridList[secondIndex], keyList[secondIndex])
|
||||
conflictList = self.conflictingHazards(grid1, grid2)
|
||||
if conflictList != []:
|
||||
return (timeRange, conflictList)
|
||||
|
||||
# if we made it to here, all is well
|
||||
return None
|
||||
|
||||
##
|
||||
# Perform checks to see if it's OK to merge hazards. If there are no conflicting
|
||||
# locks or incompatible hazards, do the merge. If there are conflicting locks,
|
||||
# generate a status bar message and quit. If there incompatible
|
||||
# hazards, show a warning and let the user decide whether to continue.
|
||||
def checkForMerge(self):
|
||||
# get the hazards selected by the forecaster
|
||||
hazParms = self.getHazardParmNames()
|
||||
|
||||
# check for empty list of hazards
|
||||
if hazParms == []:
|
||||
self.statusBarMsg("No temporary grids to merge.", "S")
|
||||
return
|
||||
|
||||
# FIXME: Lock race condition
|
||||
# check for conflicting locks
|
||||
if self._hazUtils._conflictingLocks(hazParms):
|
||||
self.statusBarMsg("There are conflicting locks. " +
|
||||
"Please resolve these before merging any hazards", "S")
|
||||
return
|
||||
|
||||
conflicts = self.checkForHazardConflicts(hazParms)
|
||||
if conflicts is None:
|
||||
# if no conflicts, merge the grids
|
||||
# We made the hazards parm immutable when we separated hazard grids.
|
||||
# It has to be made mutable to do the merge.
|
||||
parm = self.getParm(MODEL, ELEMENT, LEVEL)
|
||||
parm.setMutable(True)
|
||||
self.mergeHazardGrids()
|
||||
else:
|
||||
haz1 = string.replace(conflicts[1][0], ".", "")
|
||||
haz2 = string.replace(conflicts[1][1], ".", "")
|
||||
timeRange = str(conflicts[0])
|
||||
msg = "Hazard conflict detected!\n\n"
|
||||
msg += "Time: " + timeRange + " \n\n"
|
||||
msg += "with Hazard grids haz" + haz1 + " and haz" + haz2 + ".\n"
|
||||
|
||||
LogStream.logEvent("Merge conflict: "+ msg)
|
||||
self.displayDialog(msg)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Performs the actual merge of the temp hazards grids into the "Hazards" grid.
|
||||
def mergeHazardGrids(self):
|
||||
# get the hazards selected by the forecaster
|
||||
hazParms = self.getHazardParmNames()
|
||||
|
||||
self._hazUtils._removeAllHazardsGrids()
|
||||
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
|
||||
for tr in trList:
|
||||
byteGrid, hazKey = self.getGrids(MODEL, hazParm, LEVEL, tr,
|
||||
mode="First")
|
||||
if isinstance(hazKey, str):
|
||||
hazKey = eval(hazKey)
|
||||
|
||||
uniqueKeys = self._hazUtils._getUniqueKeys(byteGrid, hazKey)
|
||||
for uKey in uniqueKeys:
|
||||
if uKey == "<None>":
|
||||
continue
|
||||
subKeys = self._hazUtils._getSubKeys(uKey)
|
||||
for subKey in subKeys:
|
||||
# make the mask - find all areas that contain the subKey
|
||||
mask = numpy.zeros(byteGrid.shape)
|
||||
for haz in hazKey:
|
||||
if string.find(haz, subKey) >= 0:
|
||||
hazIndex = self.getIndex(haz, hazKey)
|
||||
mask = numpy.logical_or(numpy.equal(byteGrid, hazIndex), mask)
|
||||
|
||||
# make the grid
|
||||
self._hazUtils._addHazard(ELEMENT, tr, subKey, mask)
|
||||
LogStream.logEvent("merge: " + \
|
||||
str(self._hazUtils._printTime(tr.startTime().unixTime())) + " " + \
|
||||
str(self._hazUtils._printTime(tr.endTime().unixTime())) + " " + \
|
||||
subKey + "\n")
|
||||
|
||||
self.removeTempHazards()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# The main entry point of the procedure.
|
||||
def execute(self):
|
||||
self.setToolType("numeric")
|
||||
|
||||
self._hazUtils = HazardUtils.HazardUtils(self._dbss, None)
|
||||
|
||||
# see if the Hazards WE is loaded in the GFE, if not abort the tool
|
||||
if not self._hazUtils._hazardsLoaded():
|
||||
self.statusBarMsg("Hazards Weather Element must be loaded in " +\
|
||||
"the GFE before running MergeHazards", "S")
|
||||
self.cancel()
|
||||
|
||||
self.checkForMerge()
|
||||
return
|
||||
|
||||
|
||||
########################## END OF CONFIGURATION SECTION ########################
|
||||
|
||||
class Procedure(SmartScript.SmartScript):
|
||||
def __init__(self, dbss):
|
||||
SmartScript.SmartScript.__init__(self, dbss)
|
||||
self._dbss = dbss
|
||||
|
||||
##
|
||||
# Get the list of loaded temporary hazard parms
|
||||
# @return: Temporary hazard parm names, i.e., ["hazAFY"]
|
||||
# @rtype: List of Strings
|
||||
def getHazardParmNames(self):
|
||||
parms = self.loadedParms()
|
||||
hazParms = []
|
||||
for weName, level, dbID in parms:
|
||||
if string.find(weName, "haz") == 0:
|
||||
# TODO: Why is this back/forth xform needed?
|
||||
key = self._hazUtils._tempWENameToKey(weName)
|
||||
index = string.find(key, ":")
|
||||
if index != -1:
|
||||
mkey = key[0:index]
|
||||
segNum = key[index+1:]
|
||||
else:
|
||||
mkey = key
|
||||
segNum = ""
|
||||
|
||||
# append the hazard and a description
|
||||
parmName = "haz" + key
|
||||
parmName = string.replace(parmName, ".", "")
|
||||
parmName = string.replace(parmName, ":", "")
|
||||
hazParms.append(parmName)
|
||||
|
||||
return hazParms
|
||||
|
||||
##
|
||||
# Unload (delete) all the temporary hazards
|
||||
def removeTempHazards(self):
|
||||
parms = self.loadedParms()
|
||||
|
||||
toRemovePairs = []
|
||||
for weName, level, dbID in parms:
|
||||
if string.find(weName, "haz") == 0:
|
||||
toRemovePairs.append((weName, level))
|
||||
self.unloadWEs(MODEL, toRemovePairs)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# The action performed when the user opts to cancel a merge.
|
||||
# This was a callback under Tcl/tk; now displayDialog invokes
|
||||
# it directly.
|
||||
def cancelCommand(self):
|
||||
LogStream.logEvent("MergeHazards: cancel")
|
||||
return
|
||||
|
||||
##
|
||||
# The action performed when the user opts to continue a merge.
|
||||
# This was a callback under Tcl/tk; now displayDialog invokes
|
||||
# it directly.
|
||||
def continueCommand(self):
|
||||
LogStream.logEvent("MergeHazards: continue")
|
||||
parm = self.getParm(MODEL, ELEMENT, LEVEL)
|
||||
parm.setMutable(True)
|
||||
self.mergeHazardGrids()
|
||||
return
|
||||
|
||||
##
|
||||
# Displays a dialog box and queries the user to continue to merge or
|
||||
# abort the merge
|
||||
def displayDialog(self, message):
|
||||
messageBox = MessageBox(style=MessageBox.ICON_WARNING)
|
||||
messageBox.setText("MakeHazard")
|
||||
messageBox.setMessage(message)
|
||||
messageBox.setButtonLabels(["Continue Merge", "Cancel Merge"])
|
||||
messageBox.setDefaultIndex(1)
|
||||
if (messageBox.open() == 0):
|
||||
self.continueCommand()
|
||||
else:
|
||||
self.cancelCommand()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Returns the set of hazParms grids that overlap with the specified
|
||||
# timeRange.
|
||||
# @param hazParms: Hazard parm names to check
|
||||
# @type hazParms: Sequence of string
|
||||
# @param timeRange: The time range to check for overlap with
|
||||
# @type timeRange: Python TimeRange
|
||||
# @return: Byte grids and keys of the overlapping parms
|
||||
# @rtype: 2-tuple: list of byte arrays, list of list of strings
|
||||
def getOverlappingHazGrids(self, hazParms, timeRange):
|
||||
byteGridList = []
|
||||
keyList = []
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
for tr in trList:
|
||||
if tr.overlaps(timeRange):
|
||||
byteGrid, hazKey = self.getGrids(MODEL, hazParm, LEVEL,
|
||||
tr, mode="First")
|
||||
if isinstance(hazKey, str):
|
||||
hazKey = eval(hazKey)
|
||||
byteGridList.append(byteGrid)
|
||||
keyList.append(hazKey)
|
||||
|
||||
return byteGridList, keyList
|
||||
|
||||
##
|
||||
# Returns the first non-None key it finds in the keyList
|
||||
# @param keyList: Keys to search
|
||||
# @type keyList: Sequence of string
|
||||
# @return: First key that is not "<None>"
|
||||
# @rtype: string
|
||||
def getHazardKey(self, keyList):
|
||||
for k in keyList:
|
||||
if k != "<None>":
|
||||
return k
|
||||
|
||||
##
|
||||
# Checks the specified hazard grids to see if they are conflicting
|
||||
# Each grid is a tuple (byteGrid, key). Uses the configurable
|
||||
# HazardConflictDict to determine whether two hazards can be combined
|
||||
# at the same grid point. Returns an empty list if no conflict or
|
||||
# the list of hazards if they do.
|
||||
#
|
||||
# This method should really only be used internally; it assumes that
|
||||
# there is at most one key other than "<None>", and that it contains
|
||||
# a single subkey.
|
||||
#
|
||||
# @param hazGrid1: The first hazard grid
|
||||
# @type hazGrid1: 2-tuple: numpy array of int8, list of String
|
||||
# @param hazGrid2: The second hazard grid
|
||||
# @type hazGrid2: 2-tuple: numpy array of int8, list of String
|
||||
# @return: conflicting hazard names or empty list
|
||||
# @rtype: list
|
||||
def conflictingHazards(self, hazGrid1, hazGrid2):
|
||||
byteGrid1, hazKey1 = hazGrid1
|
||||
byteGrid2, hazKey2 = hazGrid2
|
||||
|
||||
key1 = self.getHazardKey(hazKey1)
|
||||
key2 = self.getHazardKey(hazKey2)
|
||||
phenSig1 = key1[0:4] # remove the etn
|
||||
phenSig2 = key2[0:4]
|
||||
|
||||
keyConflict = False
|
||||
if phenSig1 == phenSig2 and key1 != key2:
|
||||
keyConflict = True
|
||||
elif HazardsConflictDict.has_key(phenSig1):
|
||||
if phenSig2 in HazardsConflictDict[phenSig1]:
|
||||
keyConflict = True
|
||||
|
||||
if keyConflict:
|
||||
# calculate the overlap, adding the grids together will tell us if
|
||||
# there is any overlap. Any grid points > 1 are overlapped
|
||||
totalGrid = byteGrid1 + byteGrid2
|
||||
overlapMask = numpy.greater(totalGrid, 1)
|
||||
if numpy.any(overlapMask):
|
||||
return [key1, key2]
|
||||
|
||||
return []
|
||||
|
||||
##
|
||||
# See if there are any temporary hazards for the same position and time
|
||||
# that conflict with one another.
|
||||
#
|
||||
# @param hazParms: Temporary hazard parm names to check.
|
||||
# @type hazParms: sequence of string
|
||||
# @return: The first conflict, or None if there are no conflicts
|
||||
# @rtype: 2-tuple(TimeRange, list of string) or NoneType
|
||||
def checkForHazardConflicts(self, hazParms):
|
||||
timeList = []
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
for tr in trList:
|
||||
if tr.startTime().unixTime() not in timeList:
|
||||
timeList.append(tr.startTime().unixTime())
|
||||
if tr.endTime().unixTime() not in timeList:
|
||||
timeList.append(tr.endTime().unixTime())
|
||||
|
||||
timeList.sort() # sort the list
|
||||
|
||||
for t in xrange(len(timeList) - 1):
|
||||
start = timeList[t]
|
||||
end = timeList[t+1]
|
||||
timeRange = self._hazUtils._makeTimeRange(start, end)
|
||||
byteGridList = []
|
||||
keyList = []
|
||||
byteGridList, keyList = self.getOverlappingHazGrids(hazParms, timeRange)
|
||||
# compare each grid to all other grids at this timeRange
|
||||
for firstIndex in xrange(len(byteGridList) - 1):
|
||||
for secondIndex in xrange(firstIndex + 1, len(byteGridList)):
|
||||
grid1 = (byteGridList[firstIndex], keyList[firstIndex])
|
||||
grid2 = (byteGridList[secondIndex], keyList[secondIndex])
|
||||
conflictList = self.conflictingHazards(grid1, grid2)
|
||||
if conflictList != []:
|
||||
return (timeRange, conflictList)
|
||||
|
||||
# if we made it to here, all is well
|
||||
return None
|
||||
|
||||
##
|
||||
# Perform checks to see if it's OK to merge hazards. If there are no conflicting
|
||||
# locks or incompatible hazards, do the merge. If there are conflicting locks,
|
||||
# generate a status bar message and quit. If there incompatible
|
||||
# hazards, show a warning and let the user decide whether to continue.
|
||||
def checkForMerge(self):
|
||||
# get the hazards selected by the forecaster
|
||||
hazParms = self.getHazardParmNames()
|
||||
|
||||
# check for empty list of hazards
|
||||
if hazParms == []:
|
||||
self.statusBarMsg("No temporary grids to merge.", "S")
|
||||
return
|
||||
|
||||
# FIXME: Lock race condition
|
||||
# check for conflicting locks
|
||||
if self._hazUtils._conflictingLocks(hazParms):
|
||||
self.statusBarMsg("There are conflicting locks. " +
|
||||
"Please resolve these before merging any hazards", "S")
|
||||
return
|
||||
|
||||
conflicts = self.checkForHazardConflicts(hazParms)
|
||||
if conflicts is None:
|
||||
# if no conflicts, merge the grids
|
||||
# We made the hazards parm immutable when we separated hazard grids.
|
||||
# It has to be made mutable to do the merge.
|
||||
parm = self.getParm(MODEL, ELEMENT, LEVEL)
|
||||
parm.setMutable(True)
|
||||
self.mergeHazardGrids()
|
||||
else:
|
||||
haz1 = string.replace(conflicts[1][0], ".", "")
|
||||
haz2 = string.replace(conflicts[1][1], ".", "")
|
||||
timeRange = str(conflicts[0])
|
||||
msg = "Hazard conflict detected!\n\n"
|
||||
msg += "Time: " + timeRange + " \n\n"
|
||||
msg += "with Hazard grids haz" + haz1 + " and haz" + haz2 + ".\n"
|
||||
|
||||
LogStream.logEvent("Merge conflict: "+ msg)
|
||||
self.displayDialog(msg)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Performs the actual merge of the temp hazards grids into the "Hazards" grid.
|
||||
def mergeHazardGrids(self):
|
||||
# get the hazards selected by the forecaster
|
||||
hazParms = self.getHazardParmNames()
|
||||
|
||||
self._hazUtils._removeAllHazardsGrids()
|
||||
|
||||
for hazParm in hazParms:
|
||||
trList = self._hazUtils._getWEInventory(hazParm)
|
||||
|
||||
for tr in trList:
|
||||
byteGrid, hazKey = self.getGrids(MODEL, hazParm, LEVEL, tr,
|
||||
mode="First")
|
||||
if isinstance(hazKey, str):
|
||||
hazKey = eval(hazKey)
|
||||
|
||||
uniqueKeys = self._hazUtils._getUniqueKeys(byteGrid, hazKey)
|
||||
for uKey in uniqueKeys:
|
||||
if uKey == "<None>":
|
||||
continue
|
||||
subKeys = self._hazUtils._getSubKeys(uKey)
|
||||
for subKey in subKeys:
|
||||
# make the mask - find all areas that contain the subKey
|
||||
mask = numpy.zeros(byteGrid.shape)
|
||||
for haz in hazKey:
|
||||
if string.find(haz, subKey) >= 0:
|
||||
hazIndex = self.getIndex(haz, hazKey)
|
||||
mask = numpy.logical_or(numpy.equal(byteGrid, hazIndex), mask)
|
||||
|
||||
# make the grid
|
||||
self._hazUtils._addHazard(ELEMENT, tr, subKey, mask)
|
||||
LogStream.logEvent("merge: " + \
|
||||
str(self._hazUtils._printTime(tr.startTime().unixTime())) + " " + \
|
||||
str(self._hazUtils._printTime(tr.endTime().unixTime())) + " " + \
|
||||
subKey + "\n")
|
||||
|
||||
self.removeTempHazards()
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# The main entry point of the procedure.
|
||||
def execute(self):
|
||||
self.setToolType("numeric")
|
||||
|
||||
self._hazUtils = HazardUtils.HazardUtils(self._dbss, None)
|
||||
|
||||
# see if the Hazards WE is loaded in the GFE, if not abort the tool
|
||||
if not self._hazUtils._hazardsLoaded():
|
||||
self.statusBarMsg("Hazards Weather Element must be loaded in " +\
|
||||
"the GFE before running MergeHazards", "S")
|
||||
self.cancel()
|
||||
|
||||
self.checkForMerge()
|
||||
return
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
# Jun 21, 2013 14983 ryu Fixed encodeEditArea() to evaluate query
|
||||
# when necessary
|
||||
# Oct 07, 2013 2424 randerso remove use of pytz
|
||||
# Dec 23, 2013 16893 ryu Added unloadWEs() method (created by njensen)
|
||||
#
|
||||
########################################################################
|
||||
import types, string, time, sys
|
||||
|
@ -1788,6 +1789,19 @@ class SmartScript(BaseTool.BaseTool):
|
|||
parmJA[0] = parm
|
||||
self.__parmMgr.deleteParm(parmJA)
|
||||
|
||||
def unloadWEs(self, model, elementLevelPairs, mostRecent=0):
|
||||
jparms = []
|
||||
for element, level in elementLevelPairs:
|
||||
exprName = self.getExprName(model, element, level, mostRecent)
|
||||
parm = self.__parmMgr.getParmInExpr(exprName, 1)
|
||||
if parm:
|
||||
jparms.append(parm)
|
||||
if jparms:
|
||||
parmJA = jep.jarray(len(jparms), jparms[0])
|
||||
for i in xrange(len(jparms)):
|
||||
parmJA[i] = jparms[i]
|
||||
self.__parmMgr.deleteParm(parmJA)
|
||||
|
||||
def saveElements(self, elementList):
|
||||
# Save the given Fcst elements to the server
|
||||
# Example:
|
||||
|
|
|
@ -86,6 +86,7 @@
|
|||
<exclude>.*datadelivery.*</exclude>
|
||||
<exclude>.*bandwidth.*</exclude>
|
||||
<includeMode>excludeDpaAndOgc</includeMode>
|
||||
<exclude>obs-ingest-metarshef.xml</exclude>
|
||||
<!-- ncep excludes until tested -->
|
||||
<exclude>aww-ingest.xml</exclude>
|
||||
<exclude>ncairep-ingest.xml</exclude>
|
||||
|
@ -120,7 +121,8 @@
|
|||
<include>shef-ingest.xml</include>
|
||||
<include>persist-ingest.xml</include>
|
||||
<include>obs-common.xml</include>
|
||||
<include>obs-ingest.xml</include>
|
||||
<include>obs-ingest.xml</include>
|
||||
<include>obs-ingest-metarshef.xml</include>
|
||||
<include>metartohmdb-plugin.xml</include>
|
||||
<include>pointdata-common.xml</include>
|
||||
<include>shef-common.xml</include>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<beans
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
|
||||
|
||||
<bean id="obsCamelRegistered" factory-bean="contextManager" factory-method="register"
|
||||
depends-on="persistCamelRegistered,
|
||||
shefCamelRegistered,
|
||||
metarToHMDBCamelRegistered">
|
||||
<constructor-arg ref="obs-camel" />
|
||||
</bean>
|
||||
|
||||
<camelContext id="obs-camel" xmlns="http://camel.apache.org/schema/spring"
|
||||
errorHandlerRef="errorHandler" autoStartup="false">
|
||||
|
||||
<!-- Begin METAR routes -->
|
||||
<route id="metarIngestRoute">
|
||||
<from uri="jms-durable:queue:Ingest.obs" />
|
||||
<setHeader headerName="pluginName">
|
||||
<constant>obs</constant>
|
||||
</setHeader>
|
||||
<doTry>
|
||||
<pipeline>
|
||||
<bean ref="stringToFile" />
|
||||
<bean ref="obsDecoder" method="decode" />
|
||||
<bean ref="dupElim" />
|
||||
<bean ref="metarPointData" method="toPointData" />
|
||||
<multicast>
|
||||
<to uri="direct-vm:persistIndexAlert" />
|
||||
<to uri="direct-vm:metarToShef" />
|
||||
<to uri="direct-vm:metarToHMDB" />
|
||||
</multicast>
|
||||
</pipeline>
|
||||
<doCatch>
|
||||
<exception>java.lang.Throwable</exception>
|
||||
<to uri="log:metar?level=ERROR" />
|
||||
</doCatch>
|
||||
</doTry>
|
||||
</route>
|
||||
</camelContext>
|
||||
</beans>
|
|
@ -0,0 +1,41 @@
|
|||
<beans
|
||||
xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
|
||||
|
||||
<!-- This spring configuration is currently only used by the ingestHydro EDEX instance. -->
|
||||
|
||||
<bean id="obsCamelRegistered" factory-bean="contextManager" factory-method="register"
|
||||
depends-on="shefCamelRegistered,
|
||||
metarToHMDBCamelRegistered">
|
||||
<constructor-arg ref="obs-camel" />
|
||||
</bean>
|
||||
|
||||
<camelContext id="obs-camel" xmlns="http://camel.apache.org/schema/spring"
|
||||
errorHandlerRef="errorHandler" autoStartup="false">
|
||||
|
||||
<!-- Begin METAR routes -->
|
||||
<route id="metarIngestRoute">
|
||||
<from uri="jms-durable:queue:Ingest.obs" />
|
||||
<setHeader headerName="pluginName">
|
||||
<constant>obs</constant>
|
||||
</setHeader>
|
||||
<doTry>
|
||||
<pipeline>
|
||||
<bean ref="stringToFile" />
|
||||
<bean ref="obsDecoder" method="decode" />
|
||||
<bean ref="metarPointData" method="toPointData" />
|
||||
<multicast>
|
||||
<to uri="direct-vm:metarToShef" />
|
||||
<to uri="direct-vm:metarToHMDB" />
|
||||
</multicast>
|
||||
</pipeline>
|
||||
<doCatch>
|
||||
<exception>java.lang.Throwable</exception>
|
||||
<to uri="log:metar?level=ERROR" />
|
||||
</doCatch>
|
||||
</doTry>
|
||||
</route>
|
||||
</camelContext>
|
||||
</beans>
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
|
||||
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
|
||||
|
||||
|
||||
<bean id="obsDecoder" class="com.raytheon.edex.plugin.obs.ObsDecoder" />
|
||||
|
||||
<bean id="metarPointData" class="com.raytheon.edex.plugin.obs.metar.MetarPointDataTransform" />
|
||||
|
@ -14,40 +14,5 @@
|
|||
<constructor-arg value="obs" />
|
||||
<constructor-arg value="jms-durable:queue:Ingest.obs" />
|
||||
</bean>
|
||||
|
||||
<bean id="obsCamelRegistered" factory-bean="contextManager" factory-method="register"
|
||||
depends-on="persistCamelRegistered,
|
||||
shefCamelRegistered,
|
||||
metarToHMDBCamelRegistered">
|
||||
<constructor-arg ref="obs-camel" />
|
||||
</bean>
|
||||
|
||||
<camelContext id="obs-camel" xmlns="http://camel.apache.org/schema/spring"
|
||||
errorHandlerRef="errorHandler" autoStartup="false">
|
||||
|
||||
<!-- Begin METAR routes -->
|
||||
<route id="metarIngestRoute">
|
||||
<from uri="jms-durable:queue:Ingest.obs" />
|
||||
<setHeader headerName="pluginName">
|
||||
<constant>obs</constant>
|
||||
</setHeader>
|
||||
<doTry>
|
||||
<pipeline>
|
||||
<bean ref="stringToFile" />
|
||||
<bean ref="obsDecoder" method="decode" />
|
||||
<bean ref="dupElim" />
|
||||
<bean ref="metarPointData" method="toPointData" />
|
||||
<multicast>
|
||||
<to uri="direct-vm:persistIndexAlert" />
|
||||
<to uri="direct-vm:metarToShef" />
|
||||
<to uri="direct-vm:metarToHMDB" />
|
||||
</multicast>
|
||||
</pipeline>
|
||||
<doCatch>
|
||||
<exception>java.lang.Throwable</exception>
|
||||
<to uri="log:metar?level=ERROR" />
|
||||
</doCatch>
|
||||
</doTry>
|
||||
</route>
|
||||
</camelContext>
|
||||
</beans>
|
Loading…
Add table
Reference in a new issue