## # 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 = ['','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