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

396 lines
16 KiB
Python

##
# 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.
#
# CheckTandTd
#
# Author: Tom LeFebvre
#
# Version Date: 4 January 2006
# Version: 6.5
#
# 7/27/2015 yteng Use the time range selected in the Grid Manager if any
#
# ----------------------------------------------------------------------------
# The MenuItems list defines the GFE menu item(s) under which the
# Procedure is to appear.
# Possible items are: Populate, Edit, Consistency, Verify
MenuItems = ["Consistency"]
VariableList = [("Check or Force:" , "Check Only", "radio",
["Check Only", "Force: TMin<=T<=TMax\n and Td<=T"]),
]
import SmartScript
import TimeRange
import AbsTime
from JUtil import JavaWrapperClass
from numpy import *
MODEL = "Fcst"
LEVEL = "SFC"
DAY_IN_SECS = 24 * 3600
class Procedure (SmartScript.SmartScript):
def __init__(self, dbss):
SmartScript.SmartScript.__init__(self, dbss)
##
# Get the list of time ranges at the grid whose element name is WEName
# contains grids. The model and level of the weather element are assumed
# to be MODEL and LEVEL, respectively.
#
# @param WEName: Name of a weather element
# @type WEName: string
# @return: time ranges at which WEName has data.
# @rtype: Python list of Python TimeRange objects
def getWEInventory(self, WEName, timeRange=None):
if timeRange is None:
yesterday = self._gmtime() - (2 * DAY_IN_SECS) # two days ago
later = self._gmtime() + 10 * DAY_IN_SECS # 10 days from now
timeRange = TimeRange.TimeRange(yesterday, later)
if isinstance(timeRange, JavaWrapperClass):
timeRange = timeRange.toJavaObj()
parm = self.getParm(MODEL, WEName, LEVEL);
inv = parm.getGridInventory(timeRange)
trList = []
for gd in inv:
tr = TimeRange.TimeRange(gd.getGridTime())
trList.append(tr)
return trList
##
# Get time ranges locked by other workstations for the weather element named
# weName. The model for weName is taken from this object's mutableID() method;
# the level is LEVEL.
# @param weName: Name of a weather element.
# @type weName: string
# @return: time ranges locked by others
# @rtype: Python list of TimeRanges; if asJava is True, these are Java
# TimeRanges, otherwise they are Python TimeRanges.
def getLocksByOthers(self, weName):
# returns list of time ranges locked by others for this weather element
parm = self.getParm(self.mutableID(), weName, LEVEL)
if parm is None:
return []
lt = parm.getLockTable()
jlok = lt.lockedByOther();
lbo = []
for i in xrange(jlok.size()):
tr = jlok.get(i)
tr = TimeRange.TimeRange(tr)
lbo.append( tr )
return lbo
##
# Filter trList, returning only the time ranges that overlap timeRange.
# @param timeRange: the time range to test against
# @type timeRange: a Python TimeRange
# @param trList: the list of time ranges to filter
# @type trList: Python list of Python TimeRanges
# @return: The time ranges in trList that overlap timeRange.
# @rtype: a Python list of Python time ranges
def overlappingTRs(self, timeRange, trList):
newTRList = []
for tr in trList:
if timeRange.overlaps(tr):
newTRList.append(tr)
return newTRList
##
# method so that timeRanges will be sorted earliest to latest
# @param first: The first time range to compare
# @type first: Python TimeRange
# @param last: The second time range to compare
# @type last: Python TimeRange
# @return: -1 if first starts before last, 1 if first starts after last,
# and 0 if first and last start at the same time.
# @rtype: integer
def trSortMethod(self, first, last):
if first.startTime() < last.startTime():
return -1
elif first.startTime() == last.startTime():
return 0
else:
return 1
##
# Concatenate minTRList and maxTRList and sort by starting times.
# Duplicate time ranges are NOT eliminated.
# @param minTRList: time ranges of the minT grid
# @type minTRList: Python list of Python TimeRange objects.
# @param maxTRList: time ranges of the maxT grid
# @type maxTRList: Python list of Python TimeRange objects.
# @return: The combined and sorted collection.
# @rtype: Python list of Python TimeRange objects
def combineInventoryLists(self, minTRList, maxTRList):
bigList = minTRList + maxTRList
bigList.sort(self.trSortMethod)
return bigList
##
# Main entry point of this procedure. If varDict["Check or Force"] is
# "Check Only", temporary grids will be created. Otherwise, the minT, maxT,
# T, and Td grids may be changed.
# @param varDict: Determines whether temporary grids are created or
# temperature grids are modified.
# @type varDict: Python dictionary of strings to strings
def execute(self, timeRange, varDict):
checkOnly = varDict["Check or Force:"] == "Check Only"
# remove any temporary WEs we created
weList = ["TLessThanMin", "TGreaterThanMax", "TdGreaterThanT",
"MinGreaterThanMax", "MaxLessThanMin"]
for we in weList:
parm = self.getParm(MODEL, we, LEVEL)
if parm is not None:
self.unloadWE(MODEL, we, LEVEL)
self.setToolType("numeric")
if timeRange is None or not timeRange.isValid():
start = self._gmtime() - (2 * DAY_IN_SECS) # two days ago
end = self._gmtime() + (10 * DAY_IN_SECS) # 10 days from now
timeRange = TimeRange.TimeRange(start, end)
# get all the grids for all elements upfront and update as we modify
# any grids. We need to do this because the GFE caches the original
# version of all grids and there's no way yet to turn this off.
minTRList = self.getWEInventory("MinT", timeRange)
minTDict = self.getGrids(MODEL, "MinT", LEVEL, minTRList, mode = "First")
maxTRList = self.getWEInventory("MaxT", timeRange)
maxTDict = self.getGrids(MODEL, "MaxT", LEVEL, maxTRList, mode = "First")
TTRList = self.getWEInventory("T", timeRange)
tDict = self.getGrids(MODEL, "T", LEVEL, TTRList, mode = "First")
TdTRList = self.getWEInventory("Td", timeRange)
tdDict = self.getGrids(MODEL, "Td", LEVEL, TdTRList, mode = "First")
# get the all locks by other users, so we can detect they are locked
# before attempting to modify them
minTLocks = self.getLocksByOthers("MinT")
maxTLocks = self.getLocksByOthers("MaxT")
tLocks = self.getLocksByOthers("T")
tdLocks = self.getLocksByOthers("Td")
# get the list of edit areas
eaList = self.editAreaList()
# get the local WFO domain and make a mask with it
# local sites may wish to use a different maks so that a larger area
# is operated on by the tool - for example marine sites may wish to
# expand it to marine zones as well as land.
# To change the area, simply use a locally-defined edit area instead
# of self.getSiteID(). Example: siteID = "CWAPlusMarineZones"
#siteID = self.getSiteID() - this was set in A2 - changed to A1 below
siteID = "ISC_Send_Area"
if siteID in eaList: # make sure the edit area is there
siteEA = self.getEditArea(siteID) # get the edit area
siteMask = self.encodeEditArea(siteEA) # make a mask with siteEA
siteMask = siteMask.astype(bool8)
else:
topo = self.getGridShape()
siteMask = ones(topo, bool8)
print siteID, "edit area not found. Using entire GFE domain."
# Ensure that MinT <= MaxT first
minMaxList = self.combineInventoryLists(minTRList, maxTRList)
foundProblem = False
for i in xrange(0, len(minMaxList) - 1):
if minMaxList[i+1] in minTRList: # previous max modifies min
maxTR = minMaxList[i]
minTR = minMaxList[i+1]
# Make sure these TRs really exist in the inventory
if maxTR not in maxTRList:
continue
if minTR not in minTRList:
continue
minGrid = minTDict[minTR]
maxGrid = maxTDict[maxTR]
mask = (minGrid > maxGrid) & siteMask
if not sometrue(mask): # make sure some points are set
continue
foundProblem = True
if checkOnly:
self.createGrid(MODEL, "MinGreaterThanMax", "SCALAR", mask.astype(float32),
minTR, minAllowedValue=0.0, maxAllowedValue= 1.0)
else: # force the change
if minTR in minTLocks:
msg = "Can't modify MinT grid at " + str(minTR) + \
" locked by another user."
self.statusBarMsg(msg, "S")
continue
# calculate and modify the MinT grid
minGrid[mask] = maxGrid[mask]
self.createGrid(MODEL, "MinT", "SCALAR", minGrid, minTR)
minTDict[minTR] = minGrid # update the minT dictionary
elif minMaxList[i+1] in maxTRList: # previous min modifies max
minTR = minMaxList[i]
maxTR = minMaxList[i+1]
# Make sure these TRs really exist in the inventory
if maxTR not in maxTRList:
continue
if minTR not in minTRList:
continue
maxGrid = maxTDict[maxTR]
minGrid = minTDict[minTR]
mask = (maxGrid < minGrid) & siteMask
if not sometrue(mask): # make sure some points are set
continue
foundProblem = True
if checkOnly:
self.createGrid(MODEL, "MaxLessThanMin", "SCALAR", mask.astype(float32),
maxTR, minAllowedValue=0.0, maxAllowedValue= 1.0)
else: # force the change
if maxTR in maxTLocks:
msg = "Can't modify MaxT grid at " + str(maxTR) + \
" locked by another user."
self.statusBarMsg(msg, "S")
continue
# calculate and modify the MaxT grid
maxGrid[mask] = minGrid[mask]
self.createGrid(MODEL, "MaxT", "SCALAR", maxGrid, maxTR)
# update the minT dictionary with the modified minT grid
maxTDict[maxTR] = maxGrid
# Now check for T < MinT
for tr in minTRList:
minTGrid = minTDict[tr]
tInv = self.overlappingTRs(tr, TTRList)
if tInv == []: # empty list, keep going
continue
for tymeRng in tInv:
# find points in the siteMask where T < MinT
tGrid = tDict[tymeRng]
tTooLow = (tGrid < minTGrid) & siteMask
if not sometrue(tTooLow):
continue
foundProblem = True
if checkOnly: # just make a grid showing the mask where T < MinT
self.createGrid(MODEL, "TLessThanMin", "SCALAR", tTooLow.astype(float32), tymeRng,
minAllowedValue=0.0, maxAllowedValue= 1.0)
else: # force T to the MinT value
if tymeRng in tLocks:
msg = "Can't modify T grid at " + str(tymeRng) + \
" locked by another user."
self.statusBarMsg(msg, "S")
continue
tGrid[tTooLow] = minTGrid[tTooLow]
self.createGrid(MODEL, "T", "SCALAR", tGrid, tymeRng)
tDict[tymeRng] = tGrid # update the tDict
# check for T > MaxT
for tr in maxTRList:
# get the grid first
maxTGrid = maxTDict[tr]
# then warp the end time so we include T grids ending at 01z
startTime = tr.startTime()
endTime = tr.endTime().unixTime()
roundedTime = int((endTime + 43200) / 86400) * 86400 + 3600
endTime = max(endTime, roundedTime)
endTime = AbsTime.AbsTime(endTime)
timeRange = TimeRange.TimeRange(startTime, endTime)
# use the warpedTR to fetch the T inventory
tInv = self.overlappingTRs(timeRange, TTRList)
if tInv == []: # empty list, keep going
continue
for tymeRng in tInv:
# find points in the siteMask where T > MaxT
tGrid = tDict[tymeRng]
tTooHigh = (tGrid > maxTGrid) & siteMask
if not sometrue(tTooHigh): # make sure some points are set
continue
foundProblem = True
if checkOnly: # just make a grid
self.createGrid(MODEL, "TGreaterThanMax", "SCALAR", tTooHigh.astype(float32), tymeRng,
minAllowedValue=0.0, maxAllowedValue= 1.0)
else: # force T to the MaxT value
if tymeRng in tLocks:
msg = "Can't modify T grid at " + str(tymeRng) + \
" locked by another user."
self.statusBarMsg(msg, "S")
continue
tGrid[tTooHigh] = maxTGrid[tTooHigh]
self.createGrid(MODEL, "T", "SCALAR", tGrid, tymeRng)
tDict[tymeRng] = tGrid # update the tDict
# Now check T < Td
for tr in TTRList:
# make sure there's a matching Td grid
if not tr in TdTRList:
continue
tGrid = tDict[tr]
tdGrid = tdDict[tr]
# find points in the siteMask where Td > T
TdTooHigh = (tdGrid > tGrid) & siteMask
if not sometrue(TdTooHigh): # make sure some points are set
continue
foundProblem = True
if checkOnly: # just make a grid
self.createGrid(MODEL, "TdGreaterThanT", "SCALAR", TdTooHigh.astype(float32), tr,
minAllowedValue=0.0, maxAllowedValue= 1.0)
else: # force Td <= T
if tr in tdLocks:
msg = "Can't modify Td grid at " + str(tInv[i]) + \
" locked by another user."
self.statusBarMsg(msg, "S")
continue
tdGrid[TdTooHigh] = tGrid[TdTooHigh]
self.createGrid(MODEL, "Td", "SCALAR", tdGrid, tr)
tdDict[tr] = tdGrid # update the tdDict
if not foundProblem:
msg = "CheckTandTd found no inconsistencies."
self.statusBarMsg(msg, "R")