awips2/cave/com.raytheon.viz.gfe/localization/gfe/userPython/smartTools/MoveFeatureBySpeed.py
2022-05-05 12:34:50 -05:00

367 lines
15 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.
#
# MoveFeatureBySpeed
#
# Author: Thomas R. Mazza
# adapted from EditAreaAdjust tool written by
# Les Colin
# Additional Contribution: Todd Lericos
# Last Updated: Tue 10 Jun 8
# last Submitted to str: Tue 10 Jun 8
# ----------------------------------------------------------------------------
# SOFTWARE HISTORY
#
# Date Ticket# Engineer Description
# ------------- -------- --------- --------------------------------------------
# Apr 19, 2018 7271 randerso Renamed and/or removed models. Code cleanup.
#
##
##
# This is an absolute override file, indicating that a higher priority version
# of the file will completely replace a lower priority version of the file.
##
import LogStream, time
ToolType = "numeric"
WeatherElementEdited = "variableElement"
from numpy import *
ScreenList = ["SCALAR","VECTOR"]
HideTool = 1
import AbsTime
from math import *
####### CONFIGURATION SECTION #########################################################################
#
# Add or delete models according to whether or not they are available at your office.
#
sourceList = ["NAM", "GFS", "RAP", "wrfnmm", "wrfarw", "WSETA"]
threeHour = ["NAM"]
sixHour = ["GFS"]
RAP = ["RAP"]
resolution = 2.5
#
####### END CONFIGURATION SECTION #####################################################################
sourceList.append(("Fcst"))
sourceList.append(("Observed (enter below)"))
import SmartScript
## For available commands, see SmartScript
VariableList = []
VariableList.append(("Source:", "Observed (enter below)", "radio", sourceList))
VariableList.append(("Wind Level if using model:","MB700","radio",["MB925","MB850","MB700","MB500", "MB925-850", "MB850-700", "MB925-700", "MB925-500", "MB850-500", "MB700-500"]))
VariableList.append(("Movement Speed (Kts):", "15", "numeric"))
VariableList.append(("Movement Direction:" , "90", "numeric"))
VariableList.append(("Backfill upstream edges with:", "Original data", "radio", ["Original data", "Data from very edge\n(Fcst or Model only)", "Zeros"]))
# Set up Class
class Tool (SmartScript.SmartScript):
def __init__(self, dbss):
SmartScript.SmartScript.__init__(self, dbss)
def execute(self, variableElement, variableElement_GridInfo, GridTimeRange, varDict):
"Extrapolate features foward or backward in time based on observed or model speed"
self.logToolUse("Smart Tool execution")
modelList = ["NAM", "GFS", "RAP", "wrfnmm", "wrfarw", "WSETA", "Fcst"]
if varDict["Source:"] not in modelList and varDict["Source:"] != "Observed (enter below)":
modelList.append((varDict["Source:"]))
Backfill = varDict["Backfill upstream edges with:"]
xLimit = len(variableElement[0])
yLimit = len(variableElement)
#########################################################################################
#
# Get the source for the speed of motion
source = varDict["Source:"]
levels = []
if source in modelList:
site = self.getSiteID()
if source == "Fcst":
level = "SFC"
msource = source
wind = "Wind"
Wind=self.getGrids(msource,wind,level,GridTimeRange)
(speed, dir) = (Wind[0], Wind[1])
else:
#------------------------------------------------------------------------
# Modification made by CAR to handle gaps in Model grids
#--------------------------------------------------------------------------
# This section expands the range of time to look for model data to use.
# Model data is only available at certain times (e.g. NAM: 00,03,06..etc)
# Therefore, if the grid to be created is not at a time where model data
# exists...then this code expands the time range to grab the nearest model
# data. This range will be different for each model. Therefore...if models
# are added to the top this section must be changed.
#
# Edited: Todd Lericos
# Date: 3 Aug 2006
#
present = AbsTime.current()
today = AbsTime.absTimeYMD(present.year, present.month, present.day)
startTimeModel = (GridTimeRange.startTime() - today) // 3600
# print "over at Move", startTimeModel
if source in threeHour:
self.modelRange = self.createTimeRange(startTimeModel-1, startTimeModel+2, "Zulu")
elif source in sixHour:
self.modelRange = self.createTimeRange(startTimeModel-2, startTimeModel+4, "Zulu")
else:
self.modelRange = GridTimeRange
level = varDict["Wind Level if using model:"]
msource=site+"_D2D_"+source
wind = "wind"
if level in ["MB925","MB850","MB700","MB500"]:
Wind=self.getGrids(msource,wind,level,self.modelRange)
(speed, dir) = (Wind[0], Wind[1])
else:
if level == "MB925-850":
levels = self.buildLevels(950, 850, source)
elif level == "MB850-700":
levels = self.buildLevels(950, 700, source)
elif level == "MB925-700":
levels = self.buildLevels(925, 700, source)
elif level == "MB925-500":
levels = self.buildLevels(925, 500, source)
elif level == "MB850-500":
levels = self.buildLevels(850, 500, source)
elif level == "MB700-500":
levels = self.buildLevels(700, 500, source)
i = 0
j = 0
for k in range(len(levels)):
Wind=self.getGrids(msource,wind,levels[k],GridTimeRange)
(u,v)=self.MagDirToUV(Wind[0], Wind[1])
i += u
j += v
u = i / len(levels)
v = j / len(levels)
#
# convert speed/dir arrays to speed/dir arrays
#
(speed, dir) = self.UVToMagDir(u,v)
#
# convert from m/s to kts:
#
if wind == "wind": ## have model data - need to convert from m/s to kts.
speed *= 1.94384449244
else:
speed = varDict["Movement Speed (Kts):"]
dir = varDict["Movement Direction:"]
########################################################################################
#
# OK, we have the two components of motion, in kts. Now convert to kph and compute
# movement over the grid.
if source == "Observed (enter below)":
speed *= 1.852 / resolution ### 1 kt = 1.852 kph.
dir = abs(abs(360 - dir) + 90)
theta = dir % 360
rads = pi * theta / 180
x = int(self.round(speed * cos(rads), "Nearest", 1))
y = -int(self.round(speed * sin(rads), "Nearest", 1))
if type(variableElement_GridInfo) is not str:
newT = zeros(shape(variableElement),dtype=float64) - 80.0 # default value for T
if Backfill == "Zeros":
changedMask = zeros(shape(variableElement),dtype=float64) # default value for T
if x > 0 and y > 0:
newT[y:, x:] = variableElement[:-y, :-x]
if Backfill == "Zeros":
changedMask[y:, x:] = 1
elif x > 0 and y < 0:
newT[:y, x:] = variableElement[-y:, :-x]
if Backfill == "Zeros":
changedMask[:y, x:] = 1
elif x < 0 and y > 0:
newT[y:, :x] = variableElement[:-y, -x:]
if Backfill == "Zeros":
changedMask[y:, :x] = 1
elif x < 0 and y < 0:
newT[:y, :x] = variableElement[-y:, -x:]
if Backfill == "Zeros":
changedMask[:y, :x] = 1
elif x == 0 and y > 0:
newT[y:, x:] = variableElement[:-y, :]
if Backfill == "Zeros":
changedMask[y:, x:] = 1
elif x == 0 and y < 0:
newT[:y, x:] = variableElement[-y:, :]
if Backfill == "Zeros":
changedMask[:y, x:] = 1
elif x > 0 and y == 0:
newT[y:, x:] = variableElement[:, :-x]
if Backfill == "Zeros":
changedMask[y:, x:] = 1
elif x < 0 and y == 0:
newT[y:, :x] = variableElement[:, -x:]
if Backfill == "Zeros":
changedMask[y:, :x] = 1
else:
newT0 = zeros(shape(variableElement[0]),dtype=int32) - 80.0
newT1 = zeros(shape(variableElement[1]),dtype=int32) - 80.0
oldT0,oldT1 = variableElement
if Backfill == "Zeros":
changedMask = zeros(shape(variableElement),dtype=float64) # default value for T
if x > 0 and y > 0:
newT0[y:, x:] = oldT0[:-y, :-x]
newT1[y:, x:] = oldT1[:-y, :-x]
elif x > 0 and y < 0:
newT0[:y, x:] = oldT0[-y:, :-x]
newT1[:y, x:] = oldT1[-y:, :-x]
elif x < 0 and y > 0:
newT0[y:, :x] = oldT0[:-y, -x:]
newT1[y:, :x] = oldT1[:-y, -x:]
elif x < 0 and y < 0:
newT0[:y, :x] = oldT0[-y:, -x:]
newT1[:y, :x] = oldT1[-y:, -x:]
elif x == 0 and y > 0:
newT0[y:, x:] = oldT0[:-y, :]
newT1[y:, x:] = oldT1[:-y, :]
elif x == 0 and y < 0:
newT0[:y, x:] = oldT0[-y:, :]
newT1[:y, x:] = oldT1[-y:, :]
elif x > 0 and y == 0:
newT0[y:, x:] = oldT0[:, :-x]
newT1[y:, x:] = oldT1[:, :-x]
elif x < 0 and y == 0:
newT0[y:, :x] = oldT0[:, -x:]
newT1[y:, :x] = oldT1[:, -x:]
if Backfill == "Zeros":
changedMask[y:, x:] = 1
newT = newT0,newT1
else: # source is a model
speed1 = speed * 1.852 / resolution ### 1 kt = 1.852 kph.
# print "in move feature tool, missing hours ", missingHours
theta = dir % 360
(u,v)=self.MagDirToUV(speed1,theta)
u /= resolution
v /= resolution
if varDict["Movement Direction:"] < 0:
u *= -1
v *= -1
newVariableElement = zeros(shape(variableElement),dtype=int16)
if Backfill != "Original data":
changedMask = zeros(shape(variableElement),dtype=float64) + 1
for x in range(len(variableElement[0])):
for y in range(len(variableElement)):
i = u[y,x]
j = v[y,x]
a = x - i
b = y - j
a = int(clip(a,0,xLimit - 1))
b = int(clip(b,0,yLimit - 1))
newVariableElement[y,x] = variableElement[b,a]
if Backfill == "Data from very edge\n(Fcst or Model only)":
if u[y,x] > x :
newVariableElement[y,x] = newVariableElement[y,0]
if u[y,x] < 0 and u[y,x] > xLimit - x:
newVariableElement[y,x] = newVariableElement[y,xLimit]
if v[y,x] > y:
newVariableElement[y,x] = newVariableElement[0,x]
if v[y,x] < 0 and v[y,x] > yLimit - y:
newVariableElement[y,x] = newVariableElement[yLimit,x]
elif Backfill == "Zeros":
if u[y,x] > x :
changedMask[y, x] = 0
if u[y,x] < 0 and abs(u[y,x]) > xLimit - x:
changedMask[y, x] = 0
if v[y,x] > y:
changedMask[y, x] = 0
if v[y,x] < 0 and abs(v[y,x]) > yLimit - y:
changedMask[y, x] = 0
newT = newVariableElement
newT = where(less(newT, -30), variableElement, newT)
if Backfill == "Zeros":
newT[(changedMask <= 0)] = 0
# Return the new value
return newT.astype(variableElement.dtype)
def buildLevels(self, base, top, model):
plevels = []
if model in RAP:
if base == 925:
base = 950
plevel = base
while plevel >= top:
plevels.append(("MB" + str(plevel)))
plevel -= 50
else:
plevel = base
while plevel >= top:
plevels.append(("MB" + str(plevel)))
plevel -= 25
return plevels
def logToolUse(self,string):
gtime=time.gmtime()
ts="%4.4d/%2.2d/%2.2d %2.2d:%2.2d:%2.2d"%(gtime[0],gtime[1],gtime[2],
gtime[3],gtime[4],gtime[5])
LogStream.logEvent("%s| %s" % (ts,string))