301 lines
No EOL
12 KiB
Python
301 lines
No EOL
12 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 is a base file that is not intended to be overridden.
|
|
##
|
|
|
|
##
|
|
# uengine is deprecated and will be removed from the system soon. Migrate your
|
|
# apps to using the Data Access Framework (DAF).
|
|
##
|
|
|
|
#
|
|
# AtcfTrackRequest
|
|
#
|
|
# This code has been developed by the SIB for use in the AWIPS2 system.
|
|
# Request of ATCF track data.
|
|
#
|
|
# Usage:
|
|
#
|
|
#
|
|
# SOFTWARE HISTORY
|
|
#
|
|
# Date Ticket# Engineer Description
|
|
# ------------ ---------- ----------- --------------------------
|
|
# 09/07/10 284 mgamazaychikov Initial Creation
|
|
# 10/10/28 307 mgamazaychikov Updated to handle time-matching
|
|
import BaseRequest
|
|
from java.util import ArrayList
|
|
from com.raytheon.uf.common.message.response import ResponseMessageGeneric
|
|
from gov.noaa.nws.ncep.edex.uengine.utility import GempakConvert
|
|
|
|
class AtcfTrackRequest(BaseRequest.BaseRequest):
|
|
|
|
def __init__(self):
|
|
BaseRequest.BaseRequest.__init__(self, "atcf")
|
|
self.isTechniqueSet = False
|
|
self.time = None
|
|
self.StartTime = None
|
|
self.EndTime = None
|
|
self.isTimeList= False
|
|
self.AllTimesList = []
|
|
self.TimesList = []
|
|
self.Convert = GempakConvert()
|
|
|
|
def setTime(self, aTime=None):
|
|
self.time = aTime
|
|
|
|
def setStartTime(self, aTime=None):
|
|
if aTime :
|
|
self.StartTime = aTime
|
|
else:
|
|
# set StartTime to the First Available Time
|
|
self.StartTime = self.__getFirstTime()
|
|
|
|
def setEndTime(self, aTime=None):
|
|
if aTime :
|
|
self.EndTime = aTime
|
|
else:
|
|
# set StartTime to the Last Available Time
|
|
self.EndTime = self.__getLastTime()
|
|
|
|
def setTechnique(self, aTechnique):
|
|
self.technique = aTechnique
|
|
self.isTechniqueSet = True
|
|
|
|
def execute(self):
|
|
if self.time:
|
|
self.query.addParameter("dataTime", self.time)
|
|
else:
|
|
if not self.StartTime:
|
|
self.StartTime = self.__getFirstTime()
|
|
if not self.EndTime:
|
|
self.EndTime = self.__getLastTime()
|
|
if self.StartTime and self.EndTime:
|
|
self.timeRange = self.StartTime + "--" + self.EndTime
|
|
self.query.addParameter("dataTime", self.timeRange, "between")
|
|
else:
|
|
return self.__makeNullResponse("Could not set the time range")
|
|
# get the results from the database
|
|
self.queryResults = self.query.execute()
|
|
if self.queryResults is None or self.queryResults.size() == 0:
|
|
return self.__makeNullResponse()
|
|
else:
|
|
# process the results
|
|
return self.__makeResponse()
|
|
|
|
def __getFirstTime(self):
|
|
# check if the list of available times has been calculated
|
|
if self.isTimeList:
|
|
return self.Convert.dattimToDbtime(self.AllTimesList[0])
|
|
else:
|
|
# get the list of times and return the earliest available time
|
|
self.__getTimeList()
|
|
return self.Convert.dattimToDbtime(self.AllTimesList[0])
|
|
|
|
def __getLastTime(self):
|
|
# check if the list of available times has been calculated
|
|
if self.isTimeList:
|
|
return self.Convert.dattimToDbtime(self.AllTimesList[len(self.AllTimesList) -1])
|
|
else:
|
|
# get the list of times and return the last available time
|
|
self.__getTimeList()
|
|
return self.Convert.dattimToDbtime(self.AllTimesList[len(self.AllTimesList) -1])
|
|
|
|
|
|
|
|
def __getTimePlus(self, aTime, aPlus="168"):
|
|
return self.Convert.addHours(aTime, aPlus)
|
|
|
|
# def __createTimes(self):
|
|
# if self.time:
|
|
# self.TimesList.append(self.time)
|
|
# else:
|
|
# startIndex = self.AllTimesList.index(self.StartTime)
|
|
# endIndex = self.AllTimesList.index(self.EndTime)
|
|
# self.TimesList = self.AllTimesList[startIndex:endIndex]
|
|
|
|
def __getTimeList(self):
|
|
import GempakCatalogTimeQuery
|
|
tq = GempakCatalogTimeQuery.GempakCatalogTimeQuery("atcf")
|
|
tq.setReturnText()
|
|
self.AllTimesList = tq.execute().split("|")
|
|
self.isTimeList =True
|
|
|
|
def __getDictionaries(self):
|
|
import GempakSqlQuery
|
|
# list of time cyclone ID tuples:
|
|
# eg [('2010-08-28 06:00:00.0', 'EP9'), ('2010-08-28 12:00:00.0', 'EP8')]
|
|
timeIdTupleList = []
|
|
|
|
# timeIdTqDict - is the key-value dictionary of time-Id tuple Technique List dictionary
|
|
# each time has a corresponding dictionary of ID-Technique
|
|
# eg: {('2010-08-28 06:00:00.0','AL8'):['AEMI', 'AEMN', 'AP01', 'AP02'], ('2010-08-28 12:00:00.0','AL9'):['AP11', 'AP14', 'AP18']}
|
|
timeIdTqDict = {}
|
|
|
|
# idNumberDict - is the key-value dictionary of cycloneID-basin, cycloneNumb tuple pairs
|
|
# each cycloneId has a corresponding basin-cycloneNumb tuple
|
|
# eg: {'AL8': ('AL', '8'), 'AL9': ('AL', '9')}
|
|
idNumberDict = {}
|
|
|
|
for ii in range(self.queryResults.size()):
|
|
|
|
currentRecord = self.queryResults.get(ii)
|
|
|
|
# get the time
|
|
recordTime = str(currentRecord.getDataTime())
|
|
|
|
# get basin
|
|
basin = str(currentRecord.getBasin())
|
|
# get cyclone number
|
|
cycloneNumb = str(currentRecord.getCycloneNum())
|
|
|
|
# construct cyclone ID
|
|
# eg EP9
|
|
cycloneId = basin + cycloneNumb
|
|
|
|
# construct time - cyclone ID tuple
|
|
# eg ('2010-08-21 06:00:00.0', 'EP9')
|
|
timeIdTuple = (recordTime, cycloneId)
|
|
|
|
# check time - cyclone ID tuple old or new
|
|
if timeIdTuple in timeIdTupleList:
|
|
# existing time - cyclone ID tuple - do not add to list
|
|
pass
|
|
else:
|
|
timeIdTupleList.append(timeIdTuple)
|
|
|
|
# add the basin,cycloneNumb tuple as value to the idNumberDict dictionary
|
|
# for the key cycloneId, if has not been added already
|
|
if (basin, cycloneNumb) in idNumberDict.values():
|
|
pass
|
|
else:
|
|
idNumberDict[cycloneId] = (basin, cycloneNumb)
|
|
|
|
techniqueList = []
|
|
# check if the request is for a single technique
|
|
if self.isTechniqueSet:
|
|
techniqueList.append(self.technique)
|
|
else:
|
|
# perform the db query for the records with that cyclone ID
|
|
techniqueQuery = GempakSqlQuery.GempakSqlQuery()
|
|
|
|
# set the return type to text(string)
|
|
# not a ResponseMessageGEneric object
|
|
techniqueQuery.setReturnText()
|
|
|
|
# set the separator
|
|
techniqueQuery.setSeparator("|")
|
|
|
|
# set the query text
|
|
techniqueQueryText = "SELECT DISTINCT technique FROM atcf WHERE " + \
|
|
"basin ='" + idNumberDict[cycloneId][0] + "' AND " + \
|
|
"cyclonenum ='" + idNumberDict[cycloneId][1] + "' AND " + \
|
|
"reftime='" + recordTime + "'"
|
|
techniqueQuery.setQuery(techniqueQueryText)
|
|
|
|
# execute the query
|
|
techniqueQueryResults = techniqueQuery.execute()
|
|
|
|
# create a list of techniques
|
|
techniqueList = techniqueQueryResults.split("|")
|
|
|
|
# add technique as value to the to the time,cyclone ID - technique dictionary
|
|
timeIdTqDict[timeIdTuple] = techniqueList
|
|
return idNumberDict, timeIdTqDict
|
|
|
|
def __makeResponse(self):
|
|
from gov.noaa.nws.ncep.edex.uengine.tasks.atcf import AtcfCyclone, AtcfTrack
|
|
response = ArrayList()
|
|
idNumberDict, timeIdTqDict = self.__getDictionaries()
|
|
|
|
# traverse the time,cyclone ID - technique dictionary to obtain AtcfRecords and
|
|
# construct AtcfCyclone objects
|
|
for key, value in timeIdTqDict.items():
|
|
currentTime = key[0]
|
|
cycId = key[1]
|
|
techList = value
|
|
aBasin = idNumberDict[cycId][0]
|
|
aCycloneNumb = idNumberDict[cycId][1]
|
|
|
|
# create new AtcfCyclone object
|
|
aCyclone = AtcfCyclone(cycId)
|
|
for techniqueName in techList:
|
|
bsResults = None
|
|
# CARQ case
|
|
if techniqueName == "CARQ":
|
|
# first we need to create track for the past
|
|
BaseRequest.BaseRequest.__init__(self, "atcf")
|
|
self.query.addParameter("dataTime", currentTime)
|
|
self.query.addParameter("basin",aBasin)
|
|
self.query.addParameter("cycloneNum",aCycloneNumb)
|
|
self.query.addParameter("technique",techniqueName)
|
|
self.query.addParameter("radWind", "34")
|
|
self.query.addParameter("fcstHour","0", "<")
|
|
order = True
|
|
self.query.setSortBy("fcstHour", order)
|
|
bsResultsPast = self.query.execute()
|
|
bsResults = bsResultsPast
|
|
|
|
# second we need to create track for the future
|
|
BaseRequest.BaseRequest.__init__(self, "atcf")
|
|
timeRange = currentTime + "--" + self.__getTimePlus(currentTime)
|
|
self.query.addParameter("dataTime", timeRange, "between")
|
|
self.query.addParameter("basin",aBasin)
|
|
self.query.addParameter("cycloneNum",aCycloneNumb)
|
|
self.query.addParameter("technique",techniqueName)
|
|
self.query.addParameter("radWind", "34")
|
|
self.query.addParameter("fcstHour","0")
|
|
order = True
|
|
self.query.setSortBy("dataTime", order)
|
|
bsResultsFuture = self.query.execute()
|
|
count = 0
|
|
for ii in range(bsResultsFuture.size()):
|
|
recordToChange = bsResultsFuture.get(ii)
|
|
recordToChange.setFcstHour(ii*6)
|
|
bsResults.add(recordToChange)
|
|
# non-CARQ case
|
|
else:
|
|
BaseRequest.BaseRequest.__init__(self, "atcf")
|
|
self.query.addParameter("dataTime", currentTime)
|
|
self.query.addParameter("basin",aBasin)
|
|
self.query.addParameter("cycloneNum",aCycloneNumb)
|
|
self.query.addParameter("technique",techniqueName)
|
|
order = True
|
|
self.query.setSortBy("fcstHour", order)
|
|
bsResults = self.query.execute()
|
|
if bsResults is None or bsResults.size() == 0:
|
|
pass
|
|
else:
|
|
# create new AtcfTrack object
|
|
aTrack = AtcfTrack(techniqueName, bsResults)
|
|
|
|
# add AtcfTrack object to AtcfCyclone
|
|
aCyclone.addTrack(aTrack)
|
|
# add AtcfCyclone object to the response ArrayList
|
|
response.add(ResponseMessageGeneric(aCyclone))
|
|
return response
|
|
|
|
#
|
|
# Returns a string with a response message
|
|
#
|
|
def __makeNullResponse(self, aMessage="Database Query returned no results"):
|
|
return ResponseMessageGeneric(aMessage) |