awips2/cave/com.raytheon.uf.viz.derivparam.python/localization/derivedParameters/functions/Vector.py
root 9f19e3f712 Initial revision of AWIPS2 11.9.0-7p5
Former-commit-id: 64fa9254b946eae7e61bbc3f513b7c3696c4f54f
2012-01-06 08:55:05 -06:00

221 lines
No EOL
7.1 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.
##
from numpy import arctan2
from numpy import hypot
from numpy import cos
from numpy import sin
from numpy import degrees
from numpy import radians
from numpy import abs
from numpy import isscalar, empty, float32
def execute(u, v, legacyOption=None):
""" Make a vector from u,v or mag, dir.
@param legacyOption
controls how the function operates on the given u and v values.
When the legacyOption is specified and is a constant scalar value
the u and v input values are assumed to be speed and direction.
positive :: assume meteorological direction
negative :: assume mathematical direction
abs(legacyOption) == 1 :: assume degrees
abs(legacyOption) != 1 :: assume radians
abs(legacyOption) == 1 || 2 :: assume first two args are speed and
direction
Otherwise if the legacy option is not a constant, the first two
inputs are components that determine the direction, and the third
is the speed to use.
@return: tuple of (magnitude,direction,u,v)
"""
# If either u or v is a single number, expand it to match an entire Grid
if isscalar(u) and not(isscalar(v)):
tmp = empty(v.shape, float32)
tmp.fill(u)
u = tmp
if isscalar(v) and not(isscalar(u)):
tmp = empty(u.shape, float32)
tmp.fill(v)
v = tmp
# These will be parsed by legacy opts
polar=False
mathematicalDirection=False
useRadians=False
speed = None
# Handle the crazy legacy options
if legacyOption != None:
if type(legacyOption) == float:
mathematicalDirection = legacyOption < 0
useRadians = abs(legacyOption) != 1
polar = abs(legacyOption) == 1 or abs(legacyOption) == 2
elif type(legacyOption) == bool:
polar = legacyOption
else:
speed = legacyOption
completeRevolution = 360 if not useRadians else radians(360.0)
if (polar):
mag = u
dir = v
# replace all negative angles with their corresponding positive values
negDirMask = dir < 0
dir[negDirMask] = (- dir[negDirMask]) % completeRevolution
dir[negDirMask] = completeRevolution - dir[negDirMask]
dir[dir > completeRevolution] %= completeRevolution
theta = radians(dir) if not useRadians else dir
u = mag * sin(theta)
v = mag * cos(theta)
else:
u = - u if not mathematicalDirection else u
v = - v if not mathematicalDirection else v
mag = 0 if speed != None else hypot(u, v)
theta = arctan2(u, v)
dir = degrees(theta) if not useRadians else theta
dir[dir < 0] += completeRevolution
u = - u if not mathematicalDirection else u
v = - v if not mathematicalDirection else v
dir[dir == completeRevolution] = 0
if speed == None:
return (mag, dir, u, v)
else:
return execute(speed,dir,polar=True)
def test():
from numpy import array
angles = array([0., 45., 90., 135., 180., 225., 270., 315., 360., - 675., 405.])
magnitudes = angles.copy()
magnitudes[:] = 2
targetDir = array([0., 45., 90., 135., 180., 225., 270., 315., 0., 45., 45.])
targetU = array([ 0., 1.41, 2., 1.41, 0., - 1.41, - 2., - 1.41, - 0., 1.41, 1.41])
targetV = array([ 2., 1.41, 0., - 1.41, - 2., - 1.41, 0., 1.41, 2., 1.41, 1.41])
# perform regular mathematical vector tests
(mag, dir, u, v) = execute(magnitudes, angles, polar=True, mathematicalDirection=True)
if not (all(dir == targetDir) and all(u.round(2) == targetU) and all(v.round(2) == targetV)):
print dir
print targetDir
print u.round(2)
print targetU
print v.round(2)
print targetV
raise Exception
(mag, dir, u, v) = execute(u, v, mathematicalDirection=True)
if not (all(dir.round(0) == targetDir) and all(mag == magnitudes)):
raise Exception
# perform meteorological vector tests
(mag,dir,u,v) = execute(mag,dir,polar=True)
if not (all(mag == magnitudes) and
all(dir.round(0) == targetDir) and
all(u.round(2) == -targetU) and
all(v.round(2) == -targetV)):
print mag
print magnitudes
print mag == magnitudes
print dir
print targetDir
print dir == targetDir
print -u.round(2)
print targetU
print u.round(2) == -targetU
print -v.round(2)
print targetV
print v.round(2) == -targetV
raise Exception
(mag,dir,u,v) = execute(u,v)
if not (all(mag == magnitudes) and
all(dir.round(0) == targetDir) and
all(u.round(2) == -targetU) and
all(v.round(2) == -targetV)):
print mag
print magnitudes
print mag == magnitudes
print dir
print targetDir
print dir.round(0) == targetDir
print u.round(2)
print -targetU
print u.round(2) == -targetU
print v.round(2)
print -targetV
print v.round(2) == -targetV
raise Exception
# make sure the goofy legacy option works as expected
(mag,dir,u,v) = execute(mag,dir,1.0)
if not(all(u.round(2) == -targetU) and
all(v.round(2) == -targetV) and
all(mag == magnitudes) and
all(dir.round(0) == targetDir)):
raise Exception
(mag,dir,u,v) = execute(mag,dir,-1.0)
if not(all(u.round(2) == targetU) and
all(v.round(2) == targetV) and
all(mag == magnitudes) and
all(dir.round(0) == targetDir)):
print mag,dir,u,v
raise Exception
otherMag = magnitudes.copy()
otherMag[:] = 7
(mag,dir,u,v) = execute(-targetU,-targetV,otherMag)
if not(u.round(2)[0] == 0 and
v.round(2)[0] == -7 and
all(mag == otherMag) and
all(dir.round(0) == targetDir)):
print u.round(2)[0] == 0
print v.round(2)[0] == -7
print mag == otherMag
print dir.round(0)
print targetDir
print dir.round(0) == targetDir
raise Exception
print "Vector Test Complete"