519 lines
22 KiB
Python
519 lines
22 KiB
Python
|
# ----------------------------------------------------------------------------
|
||
|
# 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.
|
||
|
#
|
||
|
# WindWWUtils
|
||
|
#
|
||
|
# SOFTWARE HISTORY
|
||
|
#
|
||
|
# Date Ticket# Engineer Description
|
||
|
# ------------ ---------- ----------- ------------------------------------------
|
||
|
# May 9, 2019 21020 tlefebvr Original version
|
||
|
# May 16, 2019 21020 tlefebvr Code review changes
|
||
|
# Aug. 3, 2019 21020 tlefebvr Added breakpointZoneList
|
||
|
# Aug. 16,2019 21020 tlefebvr Code clean up.
|
||
|
# Aug 22, 2019 21020 tlefebvr Code Review changes
|
||
|
# Apr 03, 2020 21020 tlefebvr/psantos Spring 2020 Sprint
|
||
|
# Apr 29, 2020 22033 tlefebvr Added HFO breakpoints to bpZoneDict
|
||
|
# May 6, 2020 22033 tlefebvr Code clean-up. Commented out bad BP
|
||
|
# May 11, 2020 22033 tlefebvr Added new methods to track stormIDs
|
||
|
# to prevent duplicates.
|
||
|
# May 12, 2020 22033 tlefebvr Code comments.
|
||
|
# May 13, 2020 22033 tlefebvr Fixed bpDict -> bpZoneDict issue.
|
||
|
# May 14, 2020 22033 tlefebvr Added ***Sites methods for all to user.
|
||
|
# May 21, 2020 22033 tlefebvr Added more support for basins and bins
|
||
|
# Addressed code review comments.
|
||
|
# May 26, 2020 22033 tlefebvr StormID history includes gfe operating mode.
|
||
|
# May 29, 2020 22033 tlefebvr Added makeStormID for refactoring.
|
||
|
# June 3, 2020 22033 tlefebvr Addressed code review comments.
|
||
|
#
|
||
|
################################################################################
|
||
|
|
||
|
from collections import OrderedDict
|
||
|
import TropicalUtility
|
||
|
import operator
|
||
|
import functools
|
||
|
|
||
|
# This version derived from Breakpoints spreadsheet
|
||
|
bpZoneDict = OrderedDict([
|
||
|
("Mouth of the Rio Grande River - Port Mansfield" , ['TXZ257', 'TXZ256']),
|
||
|
("Port Mansfield - Baffin Bay" , ['TXZ351']),
|
||
|
("Baffin Bay - N Entrance Padre Island NS" , ['TXZ342', 'TXZ442']),
|
||
|
("N Entrance Padre Island NS - Port Aransas" , ['TXZ343', 'TXZ344', 'TXZ443']),
|
||
|
("Port Aransas - Mesquite Bay" , ['TXZ245', 'TXZ345', 'TXZ346']),
|
||
|
("Mesquite Bay - Port OConnor" , ['TXZ347', 'TXZ447']),
|
||
|
("Port OConnor - Matagorda" , ['TXZ335', 'TXZ336', 'TXZ436']),
|
||
|
("Matagorda - Sargent" , ['TXZ336', 'TXZ436']),
|
||
|
("Sargent - Freeport" , ['TXZ337', 'TXZ437']),
|
||
|
("Freeport - San Luis Pass" , ['TXZ337', 'TXZ437']),
|
||
|
("San Luis Pass - Port Bolivar" , ['TXZ313', 'TXZ338', 'TXZ438']),
|
||
|
("Port Bolivar - High Island" , ['TXZ214', 'TXZ300', 'TXZ438']),
|
||
|
("High Island - Sabine Pass" , ['TXZ215']),
|
||
|
("Sabine Pass - Cameron" , ['LAZ073']),
|
||
|
("Cameron - Intracoastal City" , ['LAZ052', 'LAZ074']),
|
||
|
("Intracoastal City - Morgan City" , ['LAZ052', 'LAZ053', 'LAZ054']),
|
||
|
("Lake Maurepas" , ['LAZ049', 'LAZ050', 'LAZ057']),
|
||
|
("Lake Pontchartrain" , ['LAZ040', 'LAZ058', 'LAZ060', 'LAZ061', 'LAZ062', 'LAZ063', 'LAZ064', 'LAZ072']),
|
||
|
("Morgan City - Grand Isle" , ['LAZ056', 'LAZ059', 'LAZ065', 'LAZ066', 'LAZ067', 'LAZ068']),
|
||
|
("Grand Isle - Mouth Mississippi River" , ['LAZ068', 'LAZ069']),
|
||
|
("Mouth Mississippi River - Mouth Pearl River" , ['LAZ069', 'LAZ070']),
|
||
|
("Mouth Pearl River - Bay St Louis" , ['MSZ080']),
|
||
|
("Bay St Louis - Ocean Springs" , ['MSZ081']),
|
||
|
("Ocean Springs - MS/AL border" , ['MSZ082']),
|
||
|
("MS/AL border - AL/FL border" , ['ALZ263', 'ALZ264', 'ALZ265', 'ALZ266']),
|
||
|
("AL/FL border - Navarre" , ['FLZ202', 'FLZ204']),
|
||
|
("Navarre - Okaloosa Walton County Line" , ['FLZ206']),
|
||
|
("Okaloosa Walton County Line - Walton Bay County Line" , ['FLZ108']),
|
||
|
("Walton Bay County Line - Panama City" , ['FLZ112']),
|
||
|
("Panama City - Mexico Beach" , ['FLZ112']),
|
||
|
("Mexico Beach - Indian Pass" , ['FLZ114']),
|
||
|
("Indian Pass - Apalachicola" , ['FLZ115']),
|
||
|
("Apalachicola - Ochlockonee River" , ['FLZ115']),
|
||
|
("Ochlockonee River - St Marks" , ['FLZ127']),
|
||
|
("St Marks - Aucilla River" , ['FLZ118', 'FLZ127']),
|
||
|
("Aucilla River - Keaton Beach" , ['FLZ128']),
|
||
|
("Keaton Beach - Steinhatchee River" , ['FLZ128']),
|
||
|
("Steinhatchee River - Suwannee River" , ['FLZ134']),
|
||
|
("Suwannee River - Yankeetown" , ['FLZ139']),
|
||
|
("Yankeetown - Chassahowitzka" , ['FLZ142']),
|
||
|
("Chassahowitzka - Aripeka" , ['FLZ148']),
|
||
|
("Aripeka - Anclote River" , ['FLZ149']),
|
||
|
("Anclote River - Egmont Key" , ['FLZ050', 'FLZ151']),
|
||
|
("Egmont Key - Anna Maria Island" , ['FLZ155']),
|
||
|
("Anna Maria Island - Middle of Longboat Key" , ['FLZ155']),
|
||
|
("Middle of Longboat Key - Englewood" , ['FLZ160']),
|
||
|
("Englewood - Boca Grande" , ['FLZ162']),
|
||
|
("Boca Grande - Bonita Beach" , ['FLZ165']),
|
||
|
("Dry Tortugas" , []),
|
||
|
("Key West - Seven Mile Bridge" , ['FLZ078']),
|
||
|
("Seven Mile Bridge - Craig Key" , ['FLZ077']),
|
||
|
("Craig Key - Key Largo" , ['FLZ076']),
|
||
|
("Key Largo - Ocean Reef" , ['FLZ076']),
|
||
|
("St Thomas and St John" , ['VIZ001']),
|
||
|
("St Croix" , ['VIZ002']),
|
||
|
("Puerto Rico" , ['PRZ001', 'PRZ002', 'PRZ003', 'PRZ004', 'PRZ005', 'PRZ006', 'PRZ007', 'PRZ008', 'PRZ009', 'PRZ010', 'PRZ011']),
|
||
|
("Culebra" , ['PRZ012']),
|
||
|
("Vieques" , ['PRZ013']),
|
||
|
("Bonita Beach - Chokoloskee" , ['FLZ069']),
|
||
|
("Chokoloskee - East Cape Sable" , ['FLZ075']),
|
||
|
("East Cape Sable - Flamingo" , ['FLZ075']),
|
||
|
("Flamingo - Card Sound Bridge" , ['FLZ174']),
|
||
|
("Card Sound Bridge - Ocean Reef Coastal" , ['FLZ173']),
|
||
|
("Ocean Reef Coastal - Golden Beach" , ['FLZ173']),
|
||
|
("Golden Beach - Hallandale Beach" , ['FLZ172']),
|
||
|
("Hallandale Beach - Deerfield Beach" , ['FLZ172']),
|
||
|
("Deerfield Beach - Boca Raton" , ['FLZ168']),
|
||
|
("Boca Raton - Jupiter Inlet" , ['FLZ168']),
|
||
|
("Jupiter Inlet - Stuart" , ['FLZ064']),
|
||
|
("Stuart - Fort Pierce" , ['FLZ059']),
|
||
|
("Fort Pierce - Vero Beach" , ['FLZ054', 'FLZ059']),
|
||
|
("Vero Beach - Sebastian Inlet" , ['FLZ054']),
|
||
|
("Sebastian Inlet - Cocoa Beach" , ['FLZ047']),
|
||
|
("Cocoa Beach - Volusia Brevard County Line" , ['FLZ147']),
|
||
|
("Volusia Brevard County Line - New Smyrna Beach" , ['FLZ141']),
|
||
|
("New Smyrna Beach - Flagler Volusia County Line" , ['FLZ141']),
|
||
|
("Flagler Volusia County Line - Marineland" , ['FLZ138']),
|
||
|
("Marineland - Crescent Beach" , ['FLZ133']),
|
||
|
("Crescent Beach - St Augustine" , ['FLZ133']),
|
||
|
("St Augustine - Ponte Vedra Beach" , ['FLZ133']),
|
||
|
("Ponte Vedra Beach - Nassau Sound" , ['FLZ125']),
|
||
|
("Nassau Sound - Mouth of St Marys River" , ['FLZ124']),
|
||
|
("Mouth of St Marys River - St Andrews Sound" , ['GAZ166']),
|
||
|
("St Andrews Sound - Altamaha Sound" , ['GAZ154']),
|
||
|
("Altamaha Sound - Savannah River" , ['GAZ116', 'GAZ117', 'GAZ118', 'GAZ119', 'GAZ138', 'GAZ139', 'GAZ140', 'GAZ141']),
|
||
|
("Savannah River - Edisto Beach" , ['SCZ047', 'SCZ048', 'SCZ049', 'SCZ051']),
|
||
|
("Edisto Beach - South Santee River" , ['SCZ045', 'SCZ050', 'SCZ052']),
|
||
|
("South Santee River - Murrells Inlet" , ['SCZ055', 'SCZ056']),
|
||
|
("Murrells Inlet - Little River Inlet" , ['SCZ054']),
|
||
|
("Little River Inlet - Cape Fear" , ['NCZ109', 'NCZ110']),
|
||
|
("Cape Fear - Surf City NC" , ['NCZ105', 'NCZ106', 'NCZ107', 'NCZ108']),
|
||
|
("Surf City NC - New River Inlet" , ['NCZ199']),
|
||
|
("New River Inlet - Bogue Inlet" , ['NCZ199']),
|
||
|
("Bogue Inlet - Cape Lookout" , ['NCZ195', 'NCZ196']),
|
||
|
("Cape Lookout - Ocracoke Inlet" , ['NCZ196']),
|
||
|
("Ocracoke Inlet - Cape Hatteras" , ['NCZ204', 'NCZ205']),
|
||
|
("Cape Hatteras - Oregon Inlet" , ['NCZ205']),
|
||
|
("Oregon Inlet - Duck" , ['NCZ203']),
|
||
|
("Pamlico Sound" , []),
|
||
|
("Albemarle Sound" , []),
|
||
|
("Duck - NC/VA border" , ['NCZ102']),
|
||
|
("NC/VA border - Cape Charles Light" , ['VAZ098']),
|
||
|
("Cape Charles Light - Parramore Island" , ['VAZ100']),
|
||
|
("Parramore Island - Chincoteague" , ['VAZ099']),
|
||
|
("Chincoteague - Fenwick Island" , ['MDZ024', 'MDZ025']),
|
||
|
("Chesapeake Bay New Point Comfort" , ['VAZ095', 'VAZ523', 'VAZ525']),
|
||
|
("Chesapeake Bay Windmill Point" , ['VAZ084', 'VAZ085', 'VAZ086']),
|
||
|
("Chesapeake Bay Smith Point" , ['VAZ077', 'VAZ078']),
|
||
|
("Chesapeake Bay Drum Point" , ['MDZ021', 'MDZ022', 'MDZ023']),
|
||
|
("Tidal Potomac Cobb Island" , ['VAZ075', 'VAZ077', 'MDZ017']),
|
||
|
("Tidal Potomac Indian Head" , ['VAZ075', 'MDZ016', 'VAZ052', 'VAZ055', 'VAZ057']),
|
||
|
("Chesapeake Bay North Beach" , ['MDZ018', 'MDZ015', 'MDZ019', 'MDZ020']),
|
||
|
("Chesapeake Bay Sandy Point" , ['MDZ014', 'MDZ012', 'MDZ015']),
|
||
|
("Chesapeake Bay Pooles Island" , ['MDZ011', 'MDZ008', 'MDZ012']),
|
||
|
("Chesa Bay North of Pooles Islnd" , ['MDZ508', 'MDZ008', 'MDZ012']),
|
||
|
("Tidal Potomac Key Bridge" , ['DCZ001','MDZ013','VAZ053', 'VAZ054']),
|
||
|
("Fenwick Island - Cape Henlopen" , ['DEZ003', 'DEZ004']),
|
||
|
("Cape Henlopen - Cape May" , ['DEZ003','DEZ004', 'NJZ023', 'NJZ024']),
|
||
|
("Cape May - Great Egg Inlet" , ['NJZ023', 'NJZ024']),
|
||
|
("Great Egg Inlet - Little Egg Inlet" , ['NJZ022', 'NJZ025']),
|
||
|
("Little Egg Inlet - Manasquan Inlet" , ['NJZ020', 'NJZ026', 'NJZ027']),
|
||
|
("Manasquan Inlet - Sandy Hook" , ['NJZ013', 'NJZ014']),
|
||
|
("Sandy Hook - East Rockaway Inlet" , ['NJZ012', 'NJZ013', 'NJZ006', 'NJZ106', 'NJZ108', 'NYZ072', 'NYZ073', 'NYZ074', 'NYZ075', 'NYZ176', 'NYZ178']),
|
||
|
("Delaware Bay South" , ['DEZ003','NJZ023']),
|
||
|
("Delaware Bay North" , ['DEZ002', 'NJZ021']),
|
||
|
("East Rockaway Inlet - Fire Island Inlet" , ['NYZ179']),
|
||
|
("Fire Island Inlet - Moriches Inlet" , ['NYZ080']),
|
||
|
("Moriches Inlet - Montauk Point" , ['NYZ081']),
|
||
|
("Montauk Point - Port Jefferson Harbor" , ['NYZ078', 'NYZ079']),
|
||
|
("Port Jefferson Harbor - Kings Point" , ['NYZ177']),
|
||
|
("Kings Point - Greenwich" , ['NYZ071']),
|
||
|
("Greenwich - New Haven" , ['CTZ009', 'CTZ010']),
|
||
|
("New Haven - Watch Hill" , ['CTZ010', 'CTZ011', 'CTZ012']),
|
||
|
("Block Island" , ['RIZ008']),
|
||
|
("Watch Hill - Point Judith" , ['RIZ006']),
|
||
|
("Point Judith - Westport" , ['RIZ006', 'RIZ007']),
|
||
|
("Nantucket" , ['MAZ024']),
|
||
|
("Marthas Vineyard" , ['MAZ023']),
|
||
|
("Westport - Woods Hole" , ['MAZ020', 'MAZ021']),
|
||
|
("Woods Hole - Chatham" , ['MAZ022']),
|
||
|
("Chatham - Provincetown" , ['MAZ022']),
|
||
|
("Provincetown - Sagamore Beach" , ['MAZ022']),
|
||
|
("Sagamore Beach - Hull" , ['MAZ019']),
|
||
|
("Hull - Gloucester" , ['MAZ007', 'MAZ015', 'MAZ016']),
|
||
|
("Gloucester - Merrimack River" , ['MAZ007']),
|
||
|
("Merrimack River - Portsmouth" , ['NHZ014']),
|
||
|
("Portsmouth - Cape Elizabeth" , ['MEZ023', 'MEZ024']),
|
||
|
("Cape Elizabeth - Port Clyde" , ['MEZ024', 'MEZ025', 'MEZ026', 'MEZ027']),
|
||
|
("Port Clyde - Stonington ME" , ['MEZ027', 'MEZ028']),
|
||
|
("Stonington ME - Petit Manan Point" , ['MEZ029']),
|
||
|
("Petit Manan Point - Eastport" , ['MEZ030']),
|
||
|
("Eastport - US Canadian Border" , ['MEZ030']),
|
||
|
("Point Piedras Blancas - Point Sal" , ['CAZ034']),
|
||
|
("Point Sal - Point Conception" , ['CAZ035']),
|
||
|
("Point Conception - Point Mugu" , ['CAZ039', 'CAZ040', 'CAZ549', 'CAZ550']),
|
||
|
("Point Mogu - Orange Los_Angeles Co_Line" , ['CAZ041']),
|
||
|
("Orange Los Angeles Co Line - San Diego Orange Co Line" , ['CAZ087','CAZ552']),
|
||
|
("San Diego Orange Co Line - US Mexico Border", ['CAZ043']),
|
||
|
|
||
|
# HFO Breakpoints / Zones
|
||
|
("Hawaii County", ['HIZ023','HIZ024','HIZ025','HIZ026','HIZ027','HIZ028']),
|
||
|
("Maui County, including the islands of Maui, Lanai, Molokai and Kahoolawe",
|
||
|
['HIZ012','HIZ013','HIZ014','HIZ015','HIZ016','HIZ017','HIZ018','HIZ019','HIZ020','HIZ021','HIZ022']),
|
||
|
("Oahu", ['HIZ005','HIZ006','HIZ007','HIZ008','HIZ009','HIZ010','HIZ011']),
|
||
|
("Kauai County, including the islands of Kauai and Niihau", ['HIZ001','HIZ002','HIZ003','HIZ004']),
|
||
|
("Johnston Atol", []),
|
||
|
("Midway Island", []),
|
||
|
("Kure Atoll", []),
|
||
|
("Palmyra Atoll", []),
|
||
|
("Teraina Atoll (Washington)", []),
|
||
|
("Tabuaeran Atoll (Fanning)", []),
|
||
|
("Kiritimati Island (Christmas)", []),
|
||
|
("Nihoa to French Frigate Shoals", []),
|
||
|
("French Frigate Shoals to Maro Reef", []),
|
||
|
("Maro Reef to Lisianski Island", []),
|
||
|
("Lisianski Island to Pearl Hermes", []),
|
||
|
])
|
||
|
|
||
|
class WindWWUtils(TropicalUtility.TropicalUtility):
|
||
|
|
||
|
def __init__(self, dbss):
|
||
|
TropicalUtility.TropicalUtility.__init__(self, dbss)
|
||
|
mode = self.gfeOperatingMode()
|
||
|
self._historyObjName = "StormIDHistory" + "_" + mode
|
||
|
self._historyCategory = "WindWWUtils"
|
||
|
|
||
|
# Defines which sites are responsible for which basins
|
||
|
self._basinDomains = {
|
||
|
"Atlantic" : ["NHA", "NHZ", "NHP"],
|
||
|
"Eastern Pacific" : ["NHA", "NHZ", "NHP"],
|
||
|
"Central Pacific" : ["HPA"],
|
||
|
"Western Pacific" : ["GUM"],
|
||
|
}
|
||
|
|
||
|
# Defines the "bins" that are used for each basin
|
||
|
self._basinBins = {
|
||
|
"Atlantic" : ["AT1", "AT2", "AT3", "AT4", "AT5"],
|
||
|
"Eastern Pacific" : ["EP1", "EP2", "EP3", "EP4", "EP5"],
|
||
|
"Central Pacific" : ["CP1", "CP2", "CP3", "CP4", "CP5"],
|
||
|
"Western Pacific" : ["WP1", "WP2", "WP3", "WP4", "WP5"],
|
||
|
}
|
||
|
|
||
|
self._maxStorms = 30
|
||
|
|
||
|
def basinNames(self):
|
||
|
"""
|
||
|
Returns the list of basin names.
|
||
|
"""
|
||
|
return self._basinDomains.keys()
|
||
|
|
||
|
def maxStorms(self):
|
||
|
return self._maxStorms
|
||
|
|
||
|
def forecastBasins(self, siteID):
|
||
|
"""
|
||
|
Returns the list of basins for which the specified siteID is responsible.
|
||
|
"""
|
||
|
basinList = []
|
||
|
for basinName, siteList in self._basinDomains.items():
|
||
|
if siteID in siteList:
|
||
|
basinList.append(basinName)
|
||
|
return basinList
|
||
|
|
||
|
def basinBins(self, basinList):
|
||
|
"""
|
||
|
Returns the list of bins defined for the given basin
|
||
|
"""
|
||
|
binList = []
|
||
|
for basinName in basinList:
|
||
|
binList.append(self._basinBins.get(basinName, None))
|
||
|
|
||
|
return binList
|
||
|
|
||
|
def etnDict(self):
|
||
|
return {
|
||
|
"AT" : 1000,
|
||
|
"EP" : 2000,
|
||
|
"CP" : 3000,
|
||
|
"WP" : 4000,
|
||
|
}
|
||
|
|
||
|
def NHCSites(self):
|
||
|
"""
|
||
|
Returns the list of NHC sites.
|
||
|
"""
|
||
|
return ["NHA", "NHZ", "NHP"]
|
||
|
|
||
|
def HFOSites(self):
|
||
|
"""
|
||
|
Returns the list of HFO sites.
|
||
|
"""
|
||
|
return ["HPA"]
|
||
|
|
||
|
def GUMSites(self):
|
||
|
"""
|
||
|
Returns the list of GUM sites.
|
||
|
"""
|
||
|
return ["GUM", "PQE", "PQW"]
|
||
|
|
||
|
def getStormInfoDicts(self):
|
||
|
"""
|
||
|
Retrieves the storm info from the JSON file. Additionally, converts all
|
||
|
the data from unicode to ordinary strings so it can be used an ordinary
|
||
|
dictionary.
|
||
|
"""
|
||
|
# Recursive method to convert unicode strings to ordinary strings
|
||
|
def decodeUnicode(object):
|
||
|
|
||
|
|
||
|
if isinstance(object, list):
|
||
|
newList = []
|
||
|
for item in object:
|
||
|
newList.append(decodeUnicode(item))
|
||
|
return newList
|
||
|
|
||
|
elif isinstance(object, tuple):
|
||
|
return tuple(decodeUnicode(list(object)))
|
||
|
|
||
|
elif isinstance(object, dict):
|
||
|
newDict = {}
|
||
|
for key in object:
|
||
|
newKey = decodeUnicode(key)
|
||
|
newDict[newKey] = decodeUnicode(object[key])
|
||
|
return newDict
|
||
|
|
||
|
return object
|
||
|
|
||
|
stormInfoList = self.extractStormInfo(filterATOnly=False)
|
||
|
|
||
|
return decodeUnicode(stormInfoList)
|
||
|
|
||
|
def breakpointZoneList(self):
|
||
|
"""
|
||
|
Return a list of all the zones included in the breakpoint dictionary (bpDict)
|
||
|
"""
|
||
|
bpValues = bpZoneDict.values()
|
||
|
# Flatten to a simple list
|
||
|
bpList = functools.reduce(operator.add, bpValues)
|
||
|
# Reduce to unique values
|
||
|
bpList = list(set(bpList))
|
||
|
|
||
|
return bpList
|
||
|
|
||
|
def createBreakpointsDict(self, filePaths):
|
||
|
"""
|
||
|
Reads the files specified in filePaths and a dictionary for easy lookup.
|
||
|
Returns a dictionary of the form (y, x) : (breakpointName, (lat, lon))
|
||
|
where (y, x) is the corresponding GFE grid point.
|
||
|
"""
|
||
|
bpDict = {}
|
||
|
bpLocations = []
|
||
|
currentCountryID = 0
|
||
|
countryDict = {}
|
||
|
|
||
|
for bpType in filePaths:
|
||
|
bpList = []
|
||
|
path = filePaths[bpType] # path for this type of BP
|
||
|
# Accumulate the file into one giant string
|
||
|
with open(path, 'r') as f:
|
||
|
text = ""
|
||
|
while f:
|
||
|
s = f.read()
|
||
|
if s == "":
|
||
|
break
|
||
|
else:
|
||
|
text = s
|
||
|
|
||
|
lines = text.split("\n") # split the one big string into one string per line
|
||
|
|
||
|
# Extract the fields for the bpName, latitude and longitude
|
||
|
for l in lines:
|
||
|
# Skip lines that don't have what we're looking for
|
||
|
if len(l) == 0: # Empty line
|
||
|
continue
|
||
|
if l[0] == "!": # Commented out line
|
||
|
continue
|
||
|
if len(l) > 72 and l[72] != "0": # A 0 in column 75 is an official breakpoint
|
||
|
continue
|
||
|
|
||
|
# Extract fields we want
|
||
|
bpName = l[16:48].strip()
|
||
|
bpName = bpName.replace("_", " ")
|
||
|
if bpName == "":
|
||
|
continue
|
||
|
|
||
|
# Extract lat/lon
|
||
|
latStr = l[56:60]
|
||
|
lonStr = l[60:67]
|
||
|
# Convert from integer to degrees
|
||
|
lat = int(latStr) / 100.0
|
||
|
lon = int(lonStr) / 100.0
|
||
|
|
||
|
x, y = self.getGridCell(lat, lon)
|
||
|
if x is None or y is None:
|
||
|
continue
|
||
|
|
||
|
countryID = l[74:76] # used to separate BP sequences
|
||
|
bpInfo = ((y, x), (bpName, lat, lon))
|
||
|
|
||
|
if (y, x) not in bpLocations: # Add it to the list
|
||
|
bpLocations.append((y, x))
|
||
|
|
||
|
bpList.append(bpInfo)
|
||
|
# See if it's a new coastline segment and if so, save the last
|
||
|
countryDict[bpName] = countryID
|
||
|
if bpType == "land":
|
||
|
# Save the last point for each segment so we can add separators
|
||
|
if countryID != currentCountryID: # new coastline segment
|
||
|
currentCountryID = countryID
|
||
|
else: # Duplicate breakpoint
|
||
|
print(bpName, lat, lon, "is a duplicate.")
|
||
|
bpDict[bpType] = bpList
|
||
|
|
||
|
latLonDict = {}
|
||
|
for bpType, bpList in filePaths.items():
|
||
|
latLonDict[bpType] = OrderedDict(bpDict[bpType])
|
||
|
|
||
|
return latLonDict, countryDict
|
||
|
|
||
|
# Returns all the storminfo objects in a dictionary. Adds an
|
||
|
# empty breakpoint entry if it's not there already
|
||
|
def fetchStormInfo(self, hazList):
|
||
|
"""
|
||
|
Fetch all the storm info dictionaries.
|
||
|
"""
|
||
|
stormInfoDictList = self.getStormInfoDicts()
|
||
|
stormInfoDicts = {}
|
||
|
for stormInfo in stormInfoDictList:
|
||
|
# Add the Breakpoints key if we don't have it.
|
||
|
if "Breakpoints" not in stormInfo:
|
||
|
stormInfo["Breakpoints"] = {}
|
||
|
for hazard in hazList:
|
||
|
if hazard == "<None>":
|
||
|
continue
|
||
|
if hazard not in stormInfo["Breakpoints"]:
|
||
|
stormInfo["Breakpoints"][hazard] = []
|
||
|
|
||
|
stormInfoDicts[stormInfo["pil"]] = stormInfo
|
||
|
|
||
|
return stormInfoDicts
|
||
|
|
||
|
def makeEditAreaName(self, bpName):
|
||
|
"""
|
||
|
Converts a breakpoint name into a string that can be used as an editArea.
|
||
|
"""
|
||
|
eaName = "WW_"
|
||
|
|
||
|
# Remove special characters
|
||
|
allowedChars = string.ascii_letters + string.digits + "_"
|
||
|
for c in bpName:
|
||
|
if c in allowedChars:
|
||
|
eaName += c
|
||
|
else:
|
||
|
eaName += "_"
|
||
|
|
||
|
return eaName
|
||
|
|
||
|
def getBPZones(self, bpDict, haz):
|
||
|
"""
|
||
|
Returns the list of zones for the specified bpDict and hazard.
|
||
|
"""
|
||
|
bpList = bpDict[haz]
|
||
|
zoneList = []
|
||
|
for bp in bpList:
|
||
|
bpZoneList = bpZoneDict.get(bp, None)
|
||
|
if bpZoneList is None:
|
||
|
continue
|
||
|
for zone in bpZoneList:
|
||
|
if zone not in zoneList:
|
||
|
zoneList.append(zone)
|
||
|
|
||
|
return zoneList
|
||
|
|
||
|
def getAdvisoryNames(self):
|
||
|
"""
|
||
|
Fetches all of the advisory names.
|
||
|
"""
|
||
|
fileNames = self._getStormAdvisoryNames() # fetch the JSON fileNames
|
||
|
# Strip the .json
|
||
|
finalList = [fileName.replace(".json", "") for fileName in fileNames]
|
||
|
return finalList
|
||
|
|
||
|
def makeStormID(self, pil, stormNumber):
|
||
|
"""
|
||
|
Makes a stormID from the specified pil and stormNumber.
|
||
|
"""
|
||
|
now = self._gmtime().unixTime()
|
||
|
yearStr = self._gmtime().strftime("%Y")
|
||
|
basinID = pil[0:2]
|
||
|
if basinID == "AT":
|
||
|
basinID = "AL"
|
||
|
|
||
|
stormID = basinID + str(stormNumber).zfill(2) + yearStr
|
||
|
|
||
|
return stormID
|
||
|
|
||
|
def stormIDHistory(self):
|
||
|
"""
|
||
|
Fetches the list of stormIDs that have been used in the past.
|
||
|
"""
|
||
|
stormIDHistoryList = []
|
||
|
try:
|
||
|
stormIDHistoryList = self.getObject(self._historyObjName, self._historyCategory)
|
||
|
except IOError: # Object was not found so make an empty one.
|
||
|
self.saveObject(self._historyObjName, stormIDHistoryList, self._historyCategory)
|
||
|
|
||
|
return stormIDHistoryList
|
||
|
|
||
|
def updateStormIDHistory(self, stormID):
|
||
|
"""
|
||
|
Updates the storm history with the specified stormID.
|
||
|
"""
|
||
|
stormIDHistoryList = self.stormIDHistory()
|
||
|
if stormID not in stormIDHistoryList:
|
||
|
stormIDHistoryList.append(stormID)
|
||
|
# Save the list
|
||
|
self.saveObject(self._historyObjName, stormIDHistoryList, self._historyCategory)
|
||
|
|
||
|
return
|