awips2/cave/com.raytheon.viz.gfe/localization/gfe/userPython/procedures/ViewWCL.py

380 lines
14 KiB
Python
Raw Normal View History

2022-05-05 12:34:50 -05:00
##
# 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
# 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
#
# 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.
#
# ViewWCL
#
# Author: Matt Davis/ARX, Tom LeFebvre - Modified to fetch inventory
#
# ----------------------------------------------------------------------------
##
# This is a base file that is not intended to be overridden.
##
# 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 os
import SmartScript, re, time
import AbsTime
import TimeRange
import tkinter
import HazardUtils
from numpy import *
class Procedure (SmartScript.SmartScript):
def __init__(self, dbss):
SmartScript.SmartScript.__init__(self, dbss)
self._dbss = dbss
# creates the various UI objects
def setUpUI(self):
self.__inventoryDict = self.getWCLInventoryDict()
# first check to see if there's any data we can plot
if len(list(self.__inventoryDict.keys())) == 0: # no entries in the dict
self.statusBarMsg("There are no current WCLs to view.", "S")
self.cancel()
return
# make the frames
self.__master = tkinter.Tk()
self.__master.title('ViewWCL')
self.__topFrame = tkinter.Frame(self.__master)
self.__topFrame.pack(side=tkinter.TOP, expand=tkinter.YES,
anchor=tkinter.N, fill=tkinter.BOTH)
self.__listFrame = tkinter.Frame(self.__topFrame, borderwidth=3,
relief=tkinter.GROOVE)
self.__buttonFrame = tkinter.Frame(self.__master)
self.makeInventoryButtons(self.__inventoryDict)
# make the buttons at the bottom of the dialog
self.makeRunButton()
self.makeRunDismissButton()
self.makeCancelButton()
self.__buttonFrame.pack(side=tkinter.TOP)
##
# Get the directory in which decoded WCLs are stored from GFE localization.
#
# @return: the WCL directory
# @rtype: string
def getWclDir(self):
# get the path manager
from com.raytheon.uf.common.localization import PathManagerFactory
pathManager = PathManagerFactory.getPathManager()
# get the proper localization context
from com.raytheon.uf.common.localization import LocalizationContext
LocalizationType = LocalizationContext.LocalizationType
CAVE_STATIC = LocalizationType.valueOf("CAVE_STATIC")
LocalizationLevel = LocalizationContext.LocalizationLevel
SITE = LocalizationLevel.valueOf("SITE")
ctx = pathManager.getContext(CAVE_STATIC, SITE)
# use localization to get the full path
wclName = os.path.join("gfe", "wcl")
wclDir = pathManager.getFile(ctx, wclName)
return wclDir.getAbsolutePath()
# gets the text inventory for WCL products and stores in a dictionary
def getWCLInventoryDict(self):
invDict = {}
wclDir = self.getWclDir()
if os.path.exists(wclDir):
for name in os.listdir(wclDir):
if re.search(r'^WCL[A-J]$', name):
absName = os.path.join(wclDir, name)
file = None
text = None
try:
file = open(absName, "r")
text = file.read(0xffff)
finally:
if file is not None:
file.close()
if text is not None:
dataDict = {}
exec(text, dataDict)
dataDict.setdefault("issueTime", 0)
dataDict.setdefault("expTime", 0)
issueTime = dataDict["issueTime"]
expTime = dataDict["expTime"]
timeDiff = (AbsTime.current().unixTime() - issueTime)
if timeDiff < 6 * 3600 and issueTime < expTime:
invDict[name] = dataDict
return invDict
# Make a button for each entry in the inventory
def makeInventoryButtons(self, invDict):
labelStr = tkinter.StringVar()
labelStr.set("Name Issuance Time")
label = tkinter.Label(self.__listFrame, textvariable=labelStr)
label.pack(side=tkinter.TOP, fill=tkinter.X, expand=tkinter.NO, padx=10,
pady=10)
invList = []
for name in invDict:
invList.append((invDict[name]['issueTime'], name))
invList.sort()
invList.reverse()
firstName = invList[0][1]
self.prodSelected = tkinter.StringVar()
for issueTime, name in invList:
timeStr = time.strftime("%a %d %b %H%MZ", time.gmtime(issueTime))
buttonStr = name + " " + timeStr
button = tkinter.Radiobutton(self.__listFrame, highlightthickness = 0,
text=buttonStr, value=name,
variable=self.prodSelected,
command=self.WCLSelected)
if name == firstName:
button.select()
button.pack(side=tkinter.TOP, anchor=tkinter.W)
self.__listFrame.pack(side=tkinter.TOP, expand=tkinter.NO,
fill=tkinter.Y, anchor=tkinter.N)
return
# called when a selection is made (does nothing)
def WCLSelected(self):
return
def _deleteWCLGrids(self):
tr = TimeRange.allTimes()
gridInfo = self.getGridInfo("WCL", "ProposedWatches", "SFC", tr)
for g in gridInfo:
self.deleteGrid("WCL", "ProposedWatches", "SFC", g.gridTime())
def makeRunButton(self):
# create the Run button
tkinter.Button(self.__buttonFrame, text="Run",
width=10, command=self.runCommand, state=tkinter.NORMAL).pack(\
side=tkinter.LEFT, pady=5, padx=10)
### Makes the Run/Dismiss buttom
def makeRunDismissButton(self):
# create the Combine button
tkinter.Button(self.__buttonFrame, text="Run/Dismiss",
width=10, command=self.runDismissCommand,
state=tkinter.NORMAL).pack(side=tkinter.LEFT, pady=5, padx=10)
### Makes the Cancel buttom
def makeCancelButton(self):
# create the Combine button
tkinter.Button(self.__buttonFrame, text="Cancel",
width=10, command=self.cancelCommand, state=tkinter.NORMAL).pack(\
side=tkinter.LEFT, pady=5, padx=10)
### called when the Run button is selected
def runCommand(self):
prodName = self.prodSelected.get()
self.plotWCL(prodName)
return
### called when the Run/Dismiss button is selected
def runDismissCommand(self):
prodName = self.prodSelected.get()
self.plotWCL(prodName)
self.cancelCommand()
### called when the Cancel button is selected
def cancelCommand(self):
# unregister the maps
self.__master.destroy()
# Main block of the tool. Sets up the UI.
def execute(self):
self._hazUtils = HazardUtils.HazardUtils(self._dbss, None)
self.setToolType("numeric")
# 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 ViewWCL", "S")
self.cancel()
self.setUpUI()
self.__master.mainloop()
return
# Does the work of plotting the watch areas. Fetches the specified text
# product, deocodes it and creates a temporary grid that shows the areas
# of the proposed watches
def plotWCL(self, productName):
#extract the data fro the dictionary
watchType = self.__inventoryDict[productName]['watchType']
expTime = self.__inventoryDict[productName]['expTime']
issueTime = self.__inventoryDict[productName]['issueTime']
finalUGCList = self.__inventoryDict[productName]['finalUGCList']
currentTime = time.time()
startTime = None
endTime = None
# This section reads the active table and decodes current watches
activeTable = self.vtecActiveTable()
# Remove unwanted data
cleanTable = []
for each in activeTable:
if 'pil' not in each:
continue
if not each['pil'] == 'WCN':
continue
if 'endTime' not in each:
continue
if each['endTime'] <= currentTime:
continue
if 'act' not in each:
continue
if each['act'] not in ['CAN', 'EXP']:
cleanTable.append(each)
if startTime is None:
startTime = each['startTime']
elif startTime > each['startTime']:
startTime = each['startTime']
if endTime is None:
endTime = each['endTime']
elif endTime > each['endTime']:
endTime = each['endTime']
# Adjust start/end times based on issueTime, expTime
if endTime is None or expTime > endTime:
endTime = expTime
if startTime is None or issueTime < startTime:
startTime = issueTime
# Round to hour
startTime = int(startTime / 3600) * 3600
# Change keys for this procedure
for each in cleanTable:
if each['phensig'] == 'SV.A':
each['phensig'] = 'sv.a'
else:
each['phensig'] = 'to.a'
# Create a master list of all IDs
watchUGCs = []
for each in cleanTable:
if each['id'] not in watchUGCs:
watchUGCs.append(each['id'])
for each in finalUGCList:
if each not in watchUGCs:
watchUGCs.append(each)
# Next, loop over the master ID list to determine the final key to
# plot.
finalKeys = []
for each in watchUGCs:
actualKey = ''
for eachRecord in cleanTable:
if eachRecord['id'] == each:
actualKey = eachRecord['phensig']
if each in finalUGCList:
if actualKey != '':
if actualKey == 'sv.a':
if watchType == 'SV.A':
actualKey = 'sv->SV'
else:
actualKey = 'sv->TO'
else:
if watchType == 'SV.A':
actualKey = 'to->SV'
else:
actualKey = 'to->TO'
else:
actualKey = watchType
finalKeys.append((each, actualKey))
# Get the ending day/time to create a timeRange. Don't have to bother
# with day groups, as watches are always < 24 hrs.
#ensure sanity
if abs(time.time() - startTime) > 43200:
startTime = int(time.time() / 3600) * 3600
if abs(time.time() - endTime) > 43200:
endTime = int(time.time() / 3600) * 3600 + (43200)
timeRange = TimeRange.TimeRange(AbsTime.AbsTime(startTime),
AbsTime.AbsTime(endTime))
# Create a dummy grid of zeros
grid = self.empty(int8)
# Define the allowed keys
keys = ['<None>','SV.A','TO.A','sv.a','to.a','to->SV','sv->SV','to->TO','sv->TO']
# Loop over the finalKeys list and plot
eaList = self.editAreaList()
for each in finalKeys:
watchIndex = self.getIndex(each[1], keys)
# Set each edit area found in the WCL to the mask value
mask = self.empty(bool)
if each[0] in eaList:
zoneArea = self.getEditArea(each[0])
zoneMask = self.encodeEditArea(zoneArea)
mask[zoneMask] = True
grid[mask] = watchIndex
#remove any existing grid
parms = self.loadedParms()
for weName, level, dbID in parms:
if weName == "ProposedWatches" and level == "SFC" and \
dbID.modelName() == "WCL":
# found parm, delete any grids
self._deleteWCLGrids()
break
self.createGrid("WCL", "ProposedWatches", "DISCRETE", (grid, keys), \
timeRange, discreteKeys=keys, discreteOverlap=0, \
discreteAuxDataLength=0)
self.setActiveElement("WCL", "ProposedWatches", "SFC", timeRange, \
colorTable='GFE/WCLHazards')
return