######################################################################## #------------------------------------------------------------------------- # Description: #------------------------------------------------------------------------- # Copying: # 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. #------------------------------------------------------------------------- # Standard and Local file names and Locations: # SPOT.TextProduct #------------------------------------------------------------------------- # User Configurable Variables:WFO,IncludeDiscussion, #------------------------------------------------------------------------- # Weather Elements Needed:SKY/WX, DEW, 20 foot winds #------------------------------------------------------------------------- # Edit Areas Needed: DEFINED BY LAT/LON INPUT #------------------------------------------------------------------------- # Associated Utilities Files e.g. Combinations file: #------------------------------------------------------------------------- # Component Products: #------------------------------------------------------------------------- # Programmers and Support including product team leader's email: Jeremy.Martin@noaa.gov #------------------------------------------------------------------------- # Development tasks that are identified and in progress: # WX ALGORITM # HAZARD HEADLINES #------------------------------------------------------------------------- # Additional Information: ORIGINAL DEVELOPER Jeremy.Martin@noaa.gov # CURRENT DEVELOPER Charlie.Paxton@noaa.gov #------------------------------------------------------------------------- # Example Output: # ## import TextRules import SampleAnalysis import SmartScript import ForecastNarrative import AreaFcst import time, string, re, os import FWFTable VariableList = [("Please enter location name__", "!!!!Location!!!!", "alphaNumeric"), ("Requested By?____________", "!!!!Requested by!!!!", "alphaNumeric"), ("Please enter the latitude_____", "27.50", "alphaNumeric"), ("Please enter the longitude___", "-81.50", "alphaNumeric"), ("Ignition Time?_____________", "0800 AM", "alphaNumeric"), ("Time to start forecast (Local Time)", "8", "scale", [0, 24]), ("Time Frame (Hours)", "2", "radio", ["2", "3", "4",]), ("Number of Periods", "4", "radio", ["3", "4", "5", "6",]), ("Forecast Issuance", "Morning", "radio", ["Early Morning", "Morning", "Late Morning", "Afternoon", "Tommorrow", "Current"]), ("Use Outlooks?", "YES", "radio", ["YES", "NO"]), ] class TextProduct(TextRules.TextRules, SampleAnalysis.SampleAnalysis): Definition = { "type": "smart", "displayName": "None", "defaultEditAreas" : [], #"DefaultPeriods" : "3", #number of periods to include "fullStationID" : "KXXX", "wfoCity" : "ANYWHERE", "wfoState" : "XX", #state abbr "wmoID" : "FNUS73", "pil" : "FWSXXX", "awipsProductID": "", "awipsTEXTDBhost": None, "includedefaultphrase" : 1, #if 1 include default phrase, 0 to leave it out "defaultphrase" : "IF CONDITIONS BECOME UNREPRESENTATIVE, CONTACT THE NATIONAL WEATHER SERVICE.", "includediscussion" : 1, #if 1 include Discussion line, if 0 leave it out "minPOP" : 0, #minimum POP for Reporting in Product, if have wx and is below minpop will report =24: ampm1 = "AM" else: ampm1 = "PM" if label2 < 12 or label2 >=24: ampm2 = "AM" else: ampm2 = "PM" if label3 < 12 or label3 >=24: ampm3 = "AM" else: ampm3 = "PM" if label4 < 12 or label4 >=24: ampm4 = "AM" else: ampm4 = "PM" if label1 == 24: label1 = 12 if label1 > 24: label1 = label1 - 24 if label1 > 12: label1 = label1 -12 if label2 == 24: label2 = 12 if label2 > 24: label2 = label2 -24 if label2 > 12: label2 = label2 - 12 if label3 == 24: label3 = 12 if label3 > 24: label3 = label3 - 24 if label3 > 12: label3 = label3 - 12 if label4 == 24: label4 = 12 if label4 > 24: label4 = label4 - 24 if label4 > 12: label4 = label4 - 12 hr1 = str(label1) +str(ampm1) if hr1 == "12PM": hr1 = "NOON" hr2 = str(label2) +str(ampm2) if hr2 == "12PM": hr2 = "NOON" hr3 = str(label3) +str(ampm3) if hr3 == "12PM": hr3 = "NOON" hr4 = str(label4) +str(ampm4) if hr4 == "12PM": hr4 = "NOON" if len(hr1) <= 4: hr1 = hr1 + " " if len(hr2) <= 4: hr2 = hr2 + " " if len(hr3) <= 4: hr3 = hr3 + " " if len(hr4) <= 4: hr4 = hr4 + " " placer = 5 while placer <= 12: namer = "dat = label" + str(placer) exec namer if dat > 24: dat = dat - 24 if dat == 24: dat = 24 if dat < 12 or dat >=24: testampm = "AM" namer = "ampm" + str(placer) + "= \"AM\"" exec namer else: testampm = "PM" namer = "ampm" + str(placer) + "= \"PM\"" exec namer if dat > 24: dat = dat -24 if dat > 12: dat = dat - 12 hrout = str(dat) + str(testampm) if hrout == "12PM": hrout = "NOON" if dat == 24: hrout = "12AM" if len(hrout) <= 4: hrout = hrout + " " namer = "hr"+ str(placer) + "= str(hrout)" exec namer placer = placer + 1 if self._useout == "YES": time2,data = self._period2[0] test = self.generateProduct("Outlook", argDict, area=editArea,timeRange=self._period2nd) sky1 = self._skywords wind1 =self._windwords wx1 = self._wxwords self._skywords = "" self._windwords = "" self._wxwords = "" test = self.generateProduct("Outlook2", argDict, area=editArea,timeRange=self._period3rd) sky2 = self._skywords wind2 = self._windwords wx2 = self._wxwords transwind = self._transwords if self._numberperiods == 6: fcst = fcst + " " + hr1 + " " + hr2 + " " + hr3 + " " + hr4 + " " + hr5 + " " + hr6 +"\n" if self._numberperiods == 5: fcst = fcst + " " + hr1 + " " + hr2 + " " + hr3 + " " + hr4 + " " + hr5 + "\n" if self._numberperiods == 4: fcst = fcst + " " + hr1 + " " + hr2 + " " + hr3 + " " + hr4 + "\n" if self._numberperiods == 3: fcst = fcst + " " + hr1 + " " + hr2 + " " + hr3 + "\n" fcst = fcst + "___________________________________________________________________\n" ###NOW THAT HEADER IS MADE GENERATE THE FORECAST### per1list = self._period1fcst(self._hourlyperiods, editArea) for item in per1list: fcst = fcst + str(item[1]) fcst = fcst + "\n" ###PERIOD 2 FIRST 12 hour outlook fcst = fcst + "___________________________________________________________________\n\n" if self._issuance == "Afternoon" and self._useout == "NO": fcst = fcst + "OUTLOOK FOR THE REST OF "+ self._dayone + " NIGHT" else: fcst = fcst + "OUTLOOK FOR "+ self._dayone + " NIGHT" if self._useout == "NO": fcst = fcst + "\nTIME(" + self._timezone + ") " fcst = fcst + " " + hr5 + " " + hr6 + " " + hr7 + " " + hr8 fcst = fcst + "\n___________________________________________________________________\n" fcst = fcst + "\n" periods = 1 if self._useout == "YES": secondperlist = self._period2fcst(self._period2,editArea,periods,sky1,wx1,wind1,transwind) else: secondperlist = self._period2hrly(self._period2tbl, editArea) ###PERIOD 3 OUTLOOK if self._useout == "YES": thirdperlist = self._period3fcst(self._period3,editArea, periods,sky2,wx2,wind2,transwind) else: thirdperlist = self._period3hrly(self._period3tbl, editArea) for item in secondperlist: fcst = fcst + str(item[1]) fcst = fcst + "___________________________________________________________________\n\n" fcst = fcst + "OUTLOOK FOR " + self._daytwo + " AFTERNOON " if self._useout == "NO": fcst = fcst + "\nTIME(" + self._timezone + ") " fcst = fcst + " " + hr9 + " " + hr10 + " " + hr11 + " " + hr12 + "\n" else: fcst = fcst + "\n" fcst = fcst + "___________________________________________________________________\n\n" for item in thirdperlist: fcst = fcst + str(item[1]) return fcst def _postProcessArea(self, fcst, editArea, areaLabel, argDict): return fcst def _postProcessProduct(self, fcst, argDict): fcst = fcst + "\n\n$$" fcst = fcst.replace("TSTM SHOWERS", "TSTM") self.storeAWIPS(fcst, self._awipsProductID, host=self._awipsTEXTDBhost) return fcst ################################################ ########ANALYSIS LIST FUNCTIONS################ ################################################ def Outlook(self): if self._issuance != "Afternoon": return { "type" : "narrative", "displayName" : None, "timePeriodMethod": self.timeRangeLabel, "methodList" : [self.assemblePhrases,self.wordWrap], "narrativeDef" : [("Phantom", 12),("outlookperiod1", 12)], } else: return { "type" : "narrative", "displayName" : None, "timePeriodMethod": self.timeRangeLabel, "methodList" : [self.assemblePhrases,self.wordWrap], "narrativeDef" : [("Phantom", 18),("outlookperiod1", 6)], } def Outlook2(self): return { "type" : "narrative", "displayName" : None, "timePeriodMethod": self.timeRangeLabel, "methodList" : [self.assemblePhrases,self.wordWrap], "narrativeDef" : [("Phantom", 24),("outlookperiod2", 12)], } def outlookperiod1(self): ###NIGHTPERIOD return { "type" : "component", "methodList" : [self.assemblePhrases,self.wordWrap], "analysisList": [ ("Sky", self.median ,[3]), ("Wx", self.rankedWx, [3]), ("Wind", self.vectorAvg), ("Wind20ft", self.vectorAvg), ("TransWind", self.vectorMedianRange, [4]), ], "phraseList" : [ self.sky_phrase, self.weather_phrase, self.standard_weather_phraseMethods, self.wind_phrase, self.transportWind_phrase, ], } def outlookperiod2(self): return { "type" : "component", "methodList" : [self.assemblePhrases,self.wordWrap], "analysisList": [ ("Sky", self.median ,[4]), ("Wx", self.rankedWx, [4]), ("Wind", self.vectorAvg), ("Wind20ft", self.vectorAvg), ("TransWind",self.vectorMedianRange, [4]), ], "phraseList" : [ self.sky_phrase, self.weather_phrase, self.wind_phrase, self.transportWind_phrase, ], } def _hourlyanalysislist(self): return [ ("T", self.avg), ("Wind", self.vectorAvg), ("Td", self.avg), ("RH", self.avg), ("Sky", self.avg), ("Wind20ft", self.vectorAvg), ("WindGust", self.maximum), ("MixHgt", self.maximum), ("PoP", self.maximum), ("TransWind", self.vectorAvg), ("VentRate", self.maximum), ("Haines", self.maximum), ("Wx", self.rankedWx), ("LDSI", self.avg), ] def _analysis12hrday(self): if self._afternoonavgmix: return [ ("Sky", self.median ,[4]), ("RH", self.minimum), ("MinRH", self.minimum), ("MaxT", self.avg), ("MinT", self.avg), ("Wx", self.rankedWx), ("Td", self.maximum), ("Wind", self.vectorAvg , [1]), ("Wind20ft", self.vectorAvg, [1]), ("WindGust", self.maximum), ("MixHgt", self.avg, [4]), ("PoP", self.maximum), ("TransWind", self.vectorAvg, [4]), ("VentRate", self.avg), ("LDSI", self.avg), #("Haines", self.maximum), ] else: return [ ("Sky", self.median ,[4]), ("RH", self.minimum), ("MinRH", self.minimum), ("MaxT", self.avg), ("MinT", self.avg), ("Wx", self.rankedWx), ("Td", self.maximum), ("Wind", self.vectorAvg , [1]), ("Wind20ft", self.vectorAvg, [1]), ("WindGust", self.maximum), ("MixHgt", self.maximum), ("PoP", self.maximum), ("TransWind", self.vectorAvg, [4]), ("VentRate", self.avg), ("LDSI", self.avg), #("Haines", self.maximum), ] def _analysis12hrnight(self): return [ ("Sky", self.median), ("RH", self.maximum), ("MaxRH", self.maximum), ("MaxT", self.avg), ("MinT", self.avg), ("Wx", self.rankedWx), #("Td", self.maximum), ("Wind", self.vectorAvg), ("Wind20ft", self.vectorAvg), ("WindGust", self.maximum), ("MixHgt", self.maximum), ("PoP", self.maximum), ("TransWind", self.vectorAvg), ("VentRate", self.avg), ("LDSI", self.avg), #("Haines", self.maximum), ] def _period1fcst(self,period,area): return [ ("SKY/WX/POP", self._skywxpophrly(period,area)), ("T", self._hourlytemp(period,area)), #("Td", self._hourlydewpt(period,area)), ("RH", self._hourlyrh(period,area)), ("WINDS", self._winds(period,area)), ("Mixing", self._hourlymixing(period,area)), ("TRANS WIND", self._transwind(period,area)), ("Dispersion Index",self._ventrate(period,area)), #("Haines", self._hainesphrase(period,area)), ] def _period2fcst(self,period,area,segments,skywords,wxwords,windwords,transwords): return [ ("SKY/WX/POP", self._summaryskywxpop(period,area)), ("MinT" , self._mint(period,area)), #("Max Dew", self._maxdew(period,area)), ("MaxRH",self._maxrh(period,area)), ("20ft wind", self._summary20ft(period,area)), ("Mixing", self._hourlymixing(period,area,segments)), ("Avg Trans Wind", self._transwind(period,area)), ("Dispersion Index", self._ventrate(period,area,segments)), #("Haines", self._hainesphrase(period,area,segments)), ] def _period3fcst(self,period,area,segments,skywords,wxwords,windwords,transwords): return [ ("SKY/WX/POP", self._summaryskywxpop(period,area)), ("MaxT" , self._maxt(period,area)), #("Min Dew", self._mindew(period,area)), ("MinRH",self._minrh(period,area)), ("20ft wind", self._summary20ft(period,area)), ("Mixing", self._hourlymixing(period,area,segments)), ("Avg Trans Wind", self._transwind(period,area)), ("Dispersion Index", self._ventrate(period,area,segments)), #("Haines", self._hainesphrase(period,area,segments)), ] def _period2hrly(self,period,area): return [ ("SKY/WX/POP", self._skywxpophrly(period,area)), ("T", self._hourlytemp(period,area)), #("Td", self._hourlydewpt(period,area)), ("RH", self._hourlyrh(period,area)), ("WINDS", self._winds(period,area)), #("Haines", self._hainesphrase(period,area)), ] def _period3hrly(self,period,area): return [ ("SKY/WX/POP", self._skywxpophrly(period,area)), ("T", self._hourlytemp(period,area)), #("Td", self._hourlydewpt(period,area)), ("RH", self._hourlyrh(period,area)), ("WINDS", self._winds(period,area)), ("Mixing", self._hourlymixing(period,area)), ("TRANS WIND", self._transwind(period,area)), ("Dispersion Index",self._ventrate(period,area)), #("Haines", self._hainesphrase(period,area)), ] ########################################################################## #### TEMPERATURE ########################################################################## def _hourlytemp(self,data,area): x = 0 wrds = "" wrds = "TEMP (F)............." while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) temp = self.getStats(dict,"T") test = str(temp) if test == "None": temp = "MM" else: temp = int(temp) temp = str(temp) if x == 0: temp = " " + temp length = len(temp) while length < 9: r = 9 - length if r != 0: temp = temp + " " else: temp = " "+ temp + " " length = len(temp) wrds = wrds + temp x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _maxt(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrday(), timerange, area) maxt = self.getStats(dict, "MaxT") wrds = "MAX TEMPERATURE (F)...." if str(maxt) == "None": maxt = " MISSING" else: maxt = str(int(maxt)) maxt = " " + maxt wrds = wrds + maxt wrds = wrds + "\n" return wrds def _mint(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrnight(), timerange, area) mint = self.getStats(dict, "MinT") wrds = "MIN TEMPERATURE (F)...." if str(mint) == "None": mint = " MISSING" else: mint = str(int(mint)) mint = " " + mint wrds = wrds + mint wrds = wrds + "\n" return wrds ########################################################################## #### DEWPOINT / RH ########################################################################## def _hourlydewpt(self,data,area): x = 0 wrds = "" wrds = "DEW PT (F)..........." while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) dew = self.getStats(dict,"Td") test = str(dew) if test == "None": dew = "MM" else: dew = int(dew) dew = str(dew) if x == 0: dew = " " + dew length = len(dew) while length < 9: r = 9 - length if r != 0: dew = dew + " " else: dew = " "+ dew + " " length = len(dew) wrds = wrds + dew x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _hourlyrh(self,data,area): x = 0 wrds = "" wrds = "RH (%)..............." while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) rh = self.getStats(dict,"RH") test = str(rh) if test == "None": rh = "MM" else: rh = int(rh) rh = str(rh) if x == 0: rh = " " + rh length = len(rh) while length < 9: r = 9 - length if r != 0: rh = rh + " " else: rh = " "+ rh + " " length = len(rh) wrds = wrds + rh x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _mindew(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrday(), timerange, area) mind = self.getStats(dict, "Td") wrds = "MIN DEW PT (F)........." if str(mind) == "None": mind = " MISSING" else: mind = str(int(mind)) mind = " " + mind wrds = wrds + mind wrds = wrds + "\n" return wrds def _maxdew(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrnight(), timerange, area) mind = self.getStats(dict, "Td") wrds = "MAX DEW PT (F)........." if str(mind) == "None": mind = " MISSING" else: mind = str(int(mind)) mind = " " + mind wrds = wrds + mind wrds = wrds + "\n" return wrds def _maxrh(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrnight(), timerange, area) rh = self.getStats(dict, "RH") wrds = "MAX RH (%)............." if str(rh) == "None": rh = " MISSING" else: rh = str(int(rh)) rh = " " + rh wrds = wrds + rh wrds = wrds + "\n" return wrds def _minrh(self,data,area): wrds = "" timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrday(), timerange, area) rh = self.getStats(dict, "RH") wrds = "MIN RH (%)............." if str(rh) == "None": rh = " MISSING" else: rh = str(int(rh)) rh = " " + rh wrds = wrds + rh wrds = wrds + "\n" return wrds ########################################################################## #### WIND / TRANSPORT WIND ########################################################################## def element_outUnits_dict(self, tree, node): dict = TextRules.TextRules.element_outUnits_dict(self, tree, node) dict["Wind"] = "mph" dict["WindGust"] = "mph" dict["Wind20ft"] = "mph" dict["TransWind"] = "mph" return dict def increment_nlValue_dict(self, tree, node): # Increment for rounding values # Units depend on the product dict = TextRules.TextRules.increment_nlValue_dict(self, tree, node) dict["Wind"] = 5 return dict def vector_mag_difference_nlValue_dict(self, tree, node): # Replaces WIND_THRESHOLD # Magnitude difference. If the difference between magnitudes # for the first and second half of a period is greater than or equal to this value, # the different magnitudes will be noted in the phrase. # Units can vary depending on the element dict = TextRules.TextRules.vector_mag_difference_nlValue_dict(self, tree, node) dict["Wind"] = 10 dict["Wind20ft"] = 10 dict["TransWind"] =10 return dict def _transwind(self,data,area): dirlist = self._winddir() x = 0 wrds = "TRANSPORT WIND (MPH)......." while x < 1: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) transwnd = self.getStats(dict,"TransWind") test = str(transwnd) if test == "None": transwnd = "MM" else: transdir = int(transwnd[1]) transwnd = float(transwnd[0]) transwnd = 1.151*transwnd transwnd = int(transwnd) transwnd = str(transwnd) dir = transdir if transwnd != "MM": for descrip in dirlist: direct = descrip[0] min = descrip[1] max = descrip[2] if direct == "N": if dir <= min or dir > max: dir = direct break else: if dir <= min and dir > max: dir = direct break if transwnd != "MM": transwnd = str(dir) + "-" + transwnd if x == 0: transwnd = " " + transwnd length = len(transwnd) while length < 9: r = 9 - length if r != 0: transwnd = transwnd + " " else: transwnd = " "+ transwnd + " " length = len(transwnd) wrds = wrds + transwnd x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _winds(self,data,area): x = 0 ft20 = "MM" reduce = self._windAdjustmentFactor dirlist = self._winddir() wrds = "20 FT WIND (MPH)....." wnd = "" while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) if self._20ftgrid: ft20 = self.getStats(dict,"Wind20ft") ft20test = str(ft20) if ft20test == "None": ft20 = "MM" wind = self.getStats(dict, "Wind") if str(wind) != "None": windspd = float(wind[0]) windspd = windspd*reduce windspd = windspd*1.151 windspd = int(windspd) winddir = int(wind[1]) if ft20 == "MM" and str(wind) != "None": ft20spd = int(windspd) ft20dir = winddir elif ft20 != "MM": ft20spd = int(ft20[0]*1.151) ft20dir = ft20[1] if ft20 != "MM" or str(wind) != "None": gusts = self.getStats(dict,"WindGust") if str(gusts) == "None": gusts = 0 tester = 0 else: gusts = int(gusts*1.151) tester = gusts - ft20spd dir = int(ft20dir) for descrip in dirlist: direct = descrip[0] min = descrip[1] max = descrip[2] testing = "test" if direct == "N": if dir <= min or dir > max: dir = direct testing = dir break else: if dir <= min and dir > max: dir = direct testing = dir break continue wnd =str(dir)+"-"+str(ft20spd) if self._includegust: if tester >= self._minimumgust: wnd = wnd + "G"+ str(gusts) else: wnd = "MM-MM" if x == 0: wnd = " " + wnd length = len(wnd) while length < 9: r = 9 - length if r != 0: wnd = wnd + " " else: wnd = " "+ wnd + " " length = len(wnd) wrds = wrds + wnd x = x + 1 wrds = string.rstrip(wrds) + "\n\n" return wrds def _summary20ft(self,data,area): x = 0 ft20 = "MM" reduce = self._windAdjustmentFactor dirlist = self._winddir() wrds = "20 FT WIND (MPH)......." wnd = "" while x < 1: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) if self._20ftgrid: ft20 = self.getStats(dict,"Wind20ft") ft20test = str(ft20) if ft20test == "None": ft20 = "MM" wind = self.getStats(dict, "Wind") if str(wind) != "None": windspd = float(wind[0]) windspd = windspd*reduce windspd = windspd*1.151 windspd = int(windspd) winddir = int(wind[1]) if ft20 == "MM" and str(wind) != "None": ft20spd = int(windspd) ft20dir = winddir elif ft20 != "MM": ft20spd = int(ft20[0]*1.151) ft20dir = ft20[1] if ft20 != "MM" or str(wind) != "None": gusts = self.getStats(dict,"WindGust") if str(gusts) == "None": gusts = 0 tester = 0 else: gusts = int(gusts*1.151) tester = gusts - ft20spd dir = int(ft20dir) for descrip in dirlist: direct = descrip[0] min = descrip[1] max = descrip[2] testing = "test" if direct == "N": if dir <= min or dir > max: dir = direct testing = dir break else: if dir <= min and dir > max: dir = direct testing = dir break continue wnd =str(dir)+"-"+str(ft20spd) if self._includegust: if tester >= self._minimumgust: wnd = wnd + "G"+ str(gusts) else: wnd = "MM-MM" if x == 0: wnd = " " + wnd length = len(wnd) while length < 9: r = 9 - length if r != 0: wnd = wnd + " " else: wnd = " "+ wnd + " " length = len(wnd) wrds = wrds + wnd x = x + 1 wrds = string.rstrip(wrds) + "\n\n" return wrds def _winddir(self): ###THIS WILL SET UP THE DIRECTION IDENTIFIERS ###FORMAT (DIR, Less THAN Equal to, Greater Than) return [ ("N", 25, 346), ("NE", 65, 26), ("E" , 115, 66), ("SE", 165, 116), ("S", 205, 166), ("SW", 255, 206), ("W", 295, 256), ("NW", 345, 296), ] def _adjustWind(self, value, mode, increment, maxFlag): # Rounding for marine winds value = value * self._windAdjustmentFactor return self.round(value, mode, increment) def rounding_method_dict(self, tree, node): # Special rounding methods # return { "Wind": self._adjustWind, } ########################################################################## #### MIXING HEIGHT ########################################################################## def _hourlymixing(self,data,area,periods=1): x = 0 wrds = "MIXING HGT (FT AGL)......" if periods == 1: wrds = wrds + ".." if periods == 1 and self._afternoonavgmix: timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrday(), timerange, area) mix = self.getStats(dict,"MixHgt") if str(mix) != "None": data = mix[1] mixingval = data[0] mixingval = int(mixingval) wrds = wrds + str(mixingval) wrds = wrds + "\n" else: wrds = wrds + "MISSING \n" return wrds while x < periods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) mix = self.getStats(dict,"MixHgt") test = str(mix) if test == "None": mix = "MM" else: mix = int(mix) mix = str(mix) if x == 0: mix = " " + mix length = len(mix) while length < 9: r = 9 - length if r != 0: mix = mix + " " else: mix = " "+ mix + " " length = len(mix) wrds = wrds + mix x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds ########################################################################## #### DISPERSION / VENTILATION / HAINES ########################################################################## def _ventrate(self,data,area,periods=1): x = 0 wrds = "" wrds = "DISPERSION INDEX........." if periods == 1: wrds = wrds + ".. " timerange,label = data[0] dict = self.getStatDict(self._sampler,self._analysis12hrday(), timerange, area) dsi = self.getStats(dict,"LDSI") test = str(dsi) if test == "None": dsi = "MM" else: dsi = int(dsi) dsi = str(dsi) wrds = wrds + str(dsi) wrds = wrds + "\n" return wrds while x < 2: timerange,label = data[0] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) dsi = self.getStats(dict,"LDSI") test = str(dsi) if test == "None": dsi = "MM" else: dsi = int(dsi) dsi = str(dsi) if x == 0: dsi = " " + dsi length = len(dsi) while length < 9: r = 9 - length if r != 0: dsi = dsi + " " else: dsi = " "+ dsi + " " length = len(dsi) wrds = wrds + dsi x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _ventratewrds(self): ### (VALUE, MIN VAL, MAX VAL) ##if values are higher than highest allowable value, highest range is used return [ ("POOR", 0 , 3000), ("FAIR", 3001, 29999), ("GOOD", 30000,60000), ("EXCELLENT", 60001, 400000), ] def _hainesphrase(self,data,area,periods=4): x = 0 haines = "" hainesphrase = self._haineswords() wrds = "HAINES INDEX........." if periods == 1: wrds = wrds + ".." while x < periods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) haines = self.getStats(dict,"Haines") if str(haines) == "None": haines = "MM" if haines != "MM": haines = int(haines) for line in hainesphrase: value = line[0] descript = line[1] if haines == value: haines = str(haines) + " (" + str(descript) + ")" break continue if x == 0: haines = " " + haines length = len(haines) while length < 9: r = 9 - length if r != 0: haines = haines + " " else: haines = " "+ haines + " " length = len(haines) wrds = wrds + haines x = x + 1 wrds = string.rstrip(wrds) + "\n" return wrds def _haineswords(self): return [ (2, "VLO"), (3, "VLO"), (4, "LOW"), (5, "MOD"), (6, "HIGH"), ] ########################################################################## #### SKY WEATHER POP ########################################################################## def wxCoverageDescriptors(self): list = TextRules.TextRules.wxCoverageDescriptors(self) list.append(("Chc", "*", "*", "*", "a chance")) return list def wxTypeDescriptors(self): list = TextRules.TextRules.wxTypeDescriptors(self) list.append( ("*", "T", "*", "Dry", "dry thunderstorms") ) list.append( ("*", "RW", "*", "*", "rain showers") ) return list def wxAttributeDescriptors(self): list = TextRules.TextRules.wxAttributeDescriptors(self) list.append( ("*", "T", "*", "Dry", "") ) return list def wxIntensityDescriptors(self): list = TextRules.TextRules.wxIntensityDescriptors(self) list.append(("*", "RW", "--", "*", "light")) return list def wxCombinations(self): ## # This is the list of which wxTypes should be combined into one. ## # For example, if ("RW", "R") appears, then wxTypes of "RW" and "R" will ## # be combined into one key and the key with the dominant coverage will ## # be used as the combined key. ## # You may also specify a method which will be ## # -- given arguments subkey1 and subkey2 and ## # -- should return ## # -- a flag = 1 if they are to be combined, 0 otherwise ## # -- the combined key to be used ## # Note: The method will be called twice, once with (subkey1, subkey2) ## # and once with (subkey2, subkey1) so you can assume one ordering. ## # See the example below, "combine_T_RW" ## # return [ ("RW", "R"), ("SW", "S"), self.combine_T_RW, ] def combine_T_RW(self, subkey1, subkey2): # Combine T and RW only if the coverage of T # is dominant over the coverage of RW wxType1 = subkey1.wxType() wxType2 = subkey2.wxType() if wxType1 == "T" and wxType2 == "RW": order = self.dominantCoverageOrder(subkey1, subkey2) if order == -1 or order == 0: return 1, subkey1 return 0, None def _allowablewx(self): ###LIST OF ALLOWABLE wx elements for Spot Burns ###USE THE IFPS CODE, it will be converted to METAR Format return [ ("T"), ("R"), ("RW"), ("S"), ("SW"), ("IP"), ("F"), ("ZF"), ("L"), ("BS"), ("BD"), ("ZL"), ("ZR"), ("H"), ("VA"), (""), ] ## def _wxcodes(self): ## ###LIST OF CODES TO BE USED WITH WX TYPES ## ######FORM (IFPS CODE, METAR CODE) ## return [ ## ("T", "TS"), ## ("R", "RA"), ## ("RW", "SHRA"), ## ("S", "SN"), ## ("SW", "SHSN"), ## ("IP", "IP"), ## ("F", "FG"), ## ("ZF","FZFG"), ## ("L", "DZ"), ## ("BS", "BLSN"), ## ("BD", "BLDU"), ## ("ZL", "FZDZ"), ## ("ZR", "FZRA"), ## ("H", "GR"), ## ("VA", "VA"), ## ("", "NO WX"), ## ] def _wxcodes(self): ###LIST OF CODES TO BE USED WITH WX TYPES ######FORM (IFPS CODE, METAR CODE) return [ ("T", "TSTM"), ("R", "RAIN"), ("RW", "SHOWERS"), ("S", "SNOW"), ("SW", "SNOW SHOWERS"), ("IP", "SLEET"), ("F", "FOG"), ("ZF", "FREEZING FOG"), ("L", "DRIZZLE"), ("BS", "BLOWING SNOW"), ("BD", "BLOWING DUST"), ("ZL", "FREEZING DRIZZLE"), ("ZR", "FREEZING RAIN"), ("H", "HAIL"), ("VA", "VA"), ("", "NO WX"), ] def _skywxpophrly(self,data,area): x = 0 sky = "" wxtest = 0 wrds = "" pops = "" obwrds = "" allowable = self._allowablewx() wxcodes = self._wxcodes() ## ################################## ## #### SKY ## ################################## while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) sky = self.getStats(dict,"Sky") wx = self.getStats(dict, "Wx") skytest = str(sky) if str(wx) != "None" and string.find(str(wx), "") != -1: wxtest = wxtest + 1 else: pass if skytest == "None": skywrds = "MM" else: sky = int(sky) if sky < 11: skywrds = "CLR" if sky >= 11 and sky < 26: skywrds = "MOCLR " if sky >= 26 and sky < 75: skywrds = "PTCLDY" if sky >= 75 and sky < 90: skywrds = "MOCLDY" if sky >= 90 : skywrds = "CLDY" if x == 0: skywrds = " " + skywrds length = len(skywrds) while length < 9: r = 9 - length if r != 0: skywrds = skywrds + " " else: skywrds = " "+ skywrds + " " length = len(skywrds) wrds = wrds + skywrds x = x + 1 #print "made it2" continue ## ################################## ## #### WX ## ################################## wx = self.getStats(dict, "Wx") ## skytest = str(sky) ## if str(wx) != "None" and string.find(str(wx), "") != -1: ## wxtest = wxtest + 1 ## else: ## pass ## if wxtest >= 6: ## wrds = "SKY/WX..............." + string.rstrip(wrds) + "\n" ## return wrds ## else: wrds = "SKY.................." + string.rstrip(wrds) + "\n" wrds = wrds + "WX..................." x = 0 obs = "" while x < self._numberperiods: #print "XXXXXXXXX", x wxwrds = "" #print "made it3" timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) wx = self.getStats(dict, "Wx") if str(wx) == "None": wx = "MM" if str(wx) == "[]": wx = "MM" if wx != "MM": wxlist = wx for place in wx: place = str(place) place = string.split(place, ":") intense = str(place[2]) type = str(place[1]) ortype = str(place[4]) if type in allowable: if type != "": for spot in wxcodes: ifps = spot[0] obcode = spot[1] if type == ifps: METAR = obcode if ortype == "OR": METAR = METAR + "/" break continue else: METAR = "NO WX" if METAR == "RW" or METAR == "SW": if intense == "--": METAR = "--" + METAR if type != "": wxwrds = wxwrds + METAR + "," else: wxwrds = wxwrds + METAR + "," elements = string.split(wxwrds, ",") thundertest = 0 thunderpresent = "False" count = 0 #print "made it4" for code in elements: if code == "TSTM": thundertest = count thunderpresent = "Yes" count = count + 1 continue count = 0 for code in elements: if code == "RA" or code == "SHOWERS": if thunderpresent == "Yes": elements[thundertest] = "TSTM" del elements[count] if code == "HAIL" and thundertest == "Yes": elements[thundertest] = element[thundertest] + code del elements[count] count = count + 1 count = 0 snowtest = 0 raintest = 0 rainpresent = "False" snowpresent = "False" for code in elements: if code == "RAIN": raintest = count rainpresent = "Yes" if code == "SNOW": snowtest = count snowpresent = "Yes" count = count + 1 count = 0 for code in elements: if code == "SHOWERS" and rainpresent == "Yes": del elements[raintest] if code == "SNOW SHOWERS" and snowpresent == "Yes": del elements[snowtest] obs = string.join(elements, " ") if wx == "MM": obs = "None" if x == 0: obs = " " + obs length = len(obs) while length < 9: r = 9 - length if r != 0: obs = obs + " " else: obs = " "+ obs + " " length = len(obs) continue obwrds = obwrds + obs x = x + 1 continue wrds = wrds + string.rstrip(obwrds) + "\n" ################################## ####POP ################################## if self._includepop: wrds = wrds + "CHANCE OF PRECIP (%)." x = 0 popwrds = "" wxpresent = "" while x < self._numberperiods: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) pop = self.getStats(dict,"PoP") wx = self.getStats(dict,"Wx") wx = str(wx) if wx == "None" or string.find(wx, "") != -1: wxpresent = "NO" else: wxpresent = "YES" if str(pop) == "None": pop = "MM" else: pop = int(pop) if pop != "MM": if pop < self._minPOP and wxpresent == "YES": pop = "<" + str(self._minPOP) elif pop < self._minPOP and wxpresent == "NO": pop = " " else: pop = str(pop) popwrds = pop if x == 0: popwrds = " " + popwrds length = len(popwrds) while length < 9: r = 9 - length if r != 0: popwrds = popwrds + " " else: popwrds = " "+ popwrds + " " length = len(popwrds) pops = pops + popwrds x = x + 1 continue wrds = wrds + string.rstrip(pops) + "\n" return wrds def _summaryskywxpop(self,data,area): #,sky,wx): wrds = "" popwrds = "" obwrds = "" pops = "" wxwrds = "" allowable = self._allowablewx() wxcodes = self._wxcodes() minPOP = self._minPOP timerange,label = data[0] x = 0 obs = "" ################################## #### SKY ################################## while x < 1: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) sky = self.getStats(dict,"Sky") skytest = str(sky) if skytest == "None": skywrds = "MM" else: sky = int(sky) if sky < 11: skywrds = "CLR" if sky >= 11 and sky < 26: skywrds = "MOCLR " if sky >= 26 and sky < 70: skywrds = "PTCLDY" if sky >= 70 and sky < 90: skywrds = "MOCLDY" if sky >= 90 : skywrds = "CLDY" if x == 0: skywrds = " " + skywrds length = len(skywrds) while length < 9: r = 9 - length if r != 0: skywrds = skywrds + " " else: skywrds = " "+ skywrds + " " length = len(skywrds) x = x + 1 continue ################################## #### WX ################################## x = 0 while x < 1: dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) wx = self.getStats(dict, "Wx") if str(wx) == "None": wx = "MM" wxwrds = "None" if str(wx) == "[]": wx = "MM" wxwrds = "None" if wx != "MM": wxlist = wx for place in wx: place = str(place) place = string.split(place, ":") intense = str(place[2]) type = str(place[1]) ortype = str(place[4]) if type in allowable: if type != "": for spot in wxcodes: ifps = spot[0] obcode = spot[1] if type == ifps: METAR = obcode if ortype == "OR": METAR = METAR + "/" break continue else: METAR = "NO WX" if METAR == "RW" or METAR == "SW": if intense == "--": METAR = "--" + METAR if type != "": wxwrds = wxwrds + METAR + "," else: wxwrds = wxwrds + METAR + "," elements = string.split(wxwrds, ",") thundertest = 0 thunderpresent = "False" count = 0 for code in elements: if code == "TSTM": thundertest = count thunderpresent = "Yes" count = count + 1 continue count = 0 for code in elements: if code == "RAIN" or code == "SHOWERS": if thunderpresent == "Yes": elements[thundertest] = "TSTM" del elements[count] if code == "GR" and thundertest == "Yes": elements[thundertest] = element[thundertest] + code del elements[count] count = count + 1 count = 0 snowtest = 0 raintest = 0 rainpresent = "False" snowpresent = "False" for code in elements: if code == "RAIN": raintest = count rainpresent = "Yes" if code == "SNOW": snowtest = count snowpresent = "Yes" count = count + 1 count = 0 for code in elements: if code == "SHOWERS" and rainpresent == "Yes": del elements[raintest] if code == "SNOW SHOWERS" and snowpresent == "Yes": del elements[snowtest] obs = string.join(elements, " ") if x == 0: obs = " " + obs length = len(obs) while length < 9: r = 9 - length if r != 0: obs = obs + " " else: obs = " "+ obs + " " length = len(obs) continue wxwrds = obwrds + obs x = x + 1 continue wxwrds = wrds + string.rstrip(wxwrds) + "\n" ################################## ####POP ################################## if self._includepop: #optional function to include pops x = 0 popwrds = "" wxpresent = "" while x < 1: timerange,label = data[x] dict = self.getStatDict(self._sampler,self._hourlyanalysislist(), timerange, area) pop = self.getStats(dict,"PoP") wx = self.getStats(dict,"Wx") wx = str(wx) if wx == "None" or string.find(wx, "") != -1: wxpresent = "NO" else: wxpresent = "YES" if str(pop) == "None": pop = "MM" else: pop = int(pop) if pop != "MM": if pop < self._minPOP and wxpresent == "YES": pop = "<" + str(self._minPOP) elif pop < self._minPOP and wxpresent == "NO": pop = " " else: pop = str(pop) popwrds = pop if x == 0: popwrds = " " + popwrds length = len(popwrds) while length < 9: r = 9 - length if r != 0: popwrds = popwrds + " " else: popwrds = " "+ popwrds + " " length = len(popwrds) popwrds = pops + popwrds x = x + 1 continue if self._includepop: if str(pop) == "None": popwrds = "MISSING" if popwrds != "MISSING": pop = int(pop) if pop < minPOP: popwrds = "LESS THAN " + str(minPOP) else: popwrds = str(pop) ################################## #### ASSEMBLE PHRASES ################################## skywrds = "SKY COVER.............. " + string.upper(skywrds) wrds =wrds + self.indentText(skywrds,"",self._spacer) wxwrds ="WEATHER................ " + string.upper(wxwrds) wrds = wrds + self.indentText(wxwrds,"",self._spacer) popwrds ="CHANCE OF PRECIP(%).... " + string.upper(popwrds) wrds = wrds + self.indentText(popwrds,"",self._spacer) return wrds ########################################################################## #### OTHER METHODS ########################################################################## def null_phrase_dict(self, tree, node): #Phrase to use for null values in subPhrases other than the first #Can be an empty string #E.g. "NORTH WINDS 20 to 25 KNOTS BECOMING LIGHT" dict = TextRules.TextRules.null_phrase_dict(self, tree, node) dict["Wind"] = "light" dict["Wx"] = "None" return dict def wordWrap(self, tree, component): # Wrap the component.words() compWords = component.get("words") if compWords is None: return compWords = self.endline(compWords, tree.get("lineLength")) return self.setWords(component, compWords) def endline(self, phrase, linelength=69, breakStr=[" ", "..."]): "Insert endlines into phrase" # Break into sub-phrases separated by \n subPhrases = string.split(phrase,"\n") # Break each sub-phrase into lines str = "" for subPhrase in subPhrases: if subPhrase == "": str = str + "\n" else: str = str + self.linebreak(subPhrase, linelength, breakStr) return str def indentText(self, text, indentFirstString = "", indentNextString = "", maxWidth=69): # indentText returns a formatted string which is at most maxWidth # columns in width, with the first line indented by "indentFirstString" # and subsequent lines indented by indentNextString. Any leading spaces # in the first line are preserved. out = '' # total output line = '' # each line # eliminate all new lines and create a list of words words = string.split(text, '\n') textData = string.join(words) words = string.split(textData) if len(words) == 0: return "" # find out how many spaces the 1st line has been indented based on # the input text. additionalIndent = string.find(text, words[0]) firstLineAdditionalIndent = '' for i in xrange(additionalIndent): i = i # for pychecker firstLineAdditionalIndent = firstLineAdditionalIndent + ' ' # now start assembling the output line = line + indentFirstString + firstLineAdditionalIndent additional = indentFirstString + firstLineAdditionalIndent for w in words: if len(line) + len(w) + 1 > maxWidth: out = out + line + "\n" line = indentNextString + w else: if len(out) == 0 and len(line) == len(additional): line = line + w #first line, don't add a space else: line = line + ' ' + w #subsequent words, add a space if len(line): out = out + line return out def getareas(self,argDict): varDict = argDict["varDict"] lat = varDict["Please enter the latitude_____"] lat = float(lat) lon = varDict["Please enter the longitude___"] lon = float(lon) #print lon names = varDict["Please enter location name__"] area = self.createLatLonArea(lat,lon,10) #print area areas = [(area, str(names)),] return areas ########################################################################## #### HAZARDS ########################################################################## def allowedHazards(self): allActions = ["NEW", "EXA", "EXB", "EXT", "UPG", "CAN", "CON", "EXP"] return [ ('HU.W', allActions, 'Tropical'), # HURRICANE WARNING ('TY.W', allActions, 'Tropical'), # TYPHOON WARNING ('TR.W', allActions, 'Tropical'), # TROPICAL STORM WARNING ('TY.Y', allActions, 'Tropical'), # TYPHOON ADVISORY ('HU.A', allActions, 'Tropical'), # HURRICANE WATCH ('TY.A', allActions, 'Tropical'), # TYPHOON WATCH ('TR.A', allActions, 'Tropical'), # TROPICAL STORM WATCH ('HI.W', allActions, 'TropicalNPW'), # INLAND HURRICANE WIND WARNING ('TI.W', allActions, 'TropicalNPW'), # INLAND TROPICAL STORM WIND WARNING ('HF.W', allActions, 'Marine'), # HURRICANE FORCE WIND WARNING ('HI.A', allActions, 'TropicalNPW'), # INLAND HURRICANE WIND WATCH ('TI.A', allActions, 'TropicalNPW'), # INLAND TROPICAL STORM WIND WATCH ('BZ.W', allActions, 'WinterWx'), # BLIZZARD WARNING ('IS.W', allActions, 'WinterWx'), # ICE STORM WARNING ('HP.W', allActions, 'WinterWx'), # HEAVY SLEET WARNING ('IP.W', allActions, 'WinterWx'), # SLEET WARNING ('LE.W', allActions, 'WinterWx'), # LAKE EFFECT SNOW WARNING ('HS.W', allActions, 'WinterWx'), # HEAVY SNOW WARNING ('WS.W', allActions, 'WinterWx'), # WINTER STORM WARNING ('ZR.Y', allActions, 'WinterWx'), # FREEZING RAIN ADVISORY ('HP.Y', allActions, 'WinterWx'), # HEAVY SLEET ADVISORY ('IP.Y', allActions, 'WinterWx'), # SLEET ADVISORY ('LE.Y', allActions, 'WinterWx'), # LAKE EFFECT SNOW ADVISORY ('SB.Y', allActions, 'WinterWx'), # SNOW AND BLOWING SNOW ADVISORY ('SN.Y', allActions, 'WinterWx'), # SNOW ADVISORY ('BS.Y', allActions, 'WinterWx'), # BLOWING SNOW ADVISORY ('WW.Y', allActions, 'WinterWx'), # WINTER WEATHER ADVISORY ('BZ.A', allActions, 'WinterWx'), # BLIZZARD WATCH ('HP.A', allActions, 'WinterWx'), # HEAVY SLEET WATCH ('LE.A', allActions, 'WinterWx'), # LAKE EFFECT SNOW WATCH ('WS.A', allActions, 'WinterWx'), # WINTER STORM WATCH ('WC.W', allActions, 'WindChill'), # WIND CHILL WARNING ('WC.Y', allActions, 'WindChill'), # WIND CHILL ADVISORY ('WC.A', allActions, 'WindChill'), # WIND CHILL WATCH ('DS.W', allActions, 'Dust'), # DUST STORM WARNING ('DU.Y', allActions, 'Dust'), # BLOWING DUST ADVISORY ('EC.W', allActions, 'Cold'), # EXTREME COLD WARNING ('EC.A', allActions, 'Cold'), # EXTREME COLD WATCH ('EH.W', allActions, 'Heat'), # EXCESSIVE HEAT WARNING ('EH.A', allActions, 'Heat'), # EXCESSIVE HEAT WATCH ('HT.Y', allActions, 'Heat'), # HEAT ADVISORY ('FG.Y', allActions, 'Fog'), # DENSE FOG ADVISORY ('FZ.W', allActions, 'FrostFreeze'), # FREEZE WARNING ('FR.W', allActions, 'FrostFreeze'), # FROST WARNING ('FR.Y', allActions, 'FrostFreeze'), # FROST ADVISORY ('FZ.A', allActions, 'FrostFreeze'), # FREEZE WATCH ('HW.W', allActions, 'Wind'), # HIGH WIND WARNING ('WI.Y', allActions, 'Wind'), # WIND ADVISORY ('LW.Y', allActions, 'Wind'), # LAKE WIND ADVISORY ('HW.A', allActions, 'Wind'), # HIGH WIND WATCH ('SM.Y', allActions, 'Smoke'), # DENSE SMOKE ADVISORY ('ZF.Y', allActions, 'FreezeFog'), # FREEZING FOG ADVISORY ('FL.W', allActions, 'Flood'), # FLOOD WARNING ('FF.A', allActions, 'Flood'), # FLASH FLOOD WATCH ('FL.A', allActions, 'Flood'), # FLOOD WATCH ('CF.W', allActions, 'CoastalFlood'), # COASTAL FLOOD WARNING ('LS.W', allActions, 'CoastalFlood'), # LAKESHORE FLOOD WARNING ('CF.A', allActions, 'CoastalFlood'), # COASTAL FLOOD WATCH ('LS.A', allActions, 'CoastalFlood'), # LAKESHORE FLOOD WATCH ('UP.W', allActions, 'IceAccr'), # ICE ACCRETION WARNING ('UP.Y', allActions, 'IceAccr'), # ICE ACCRETION ADVISORY ('AV.W', allActions, 'Avalanche'), # AVALANCHE WARNING ('AV.Y', allActions, 'Avalanche'), # AVALANCHE ADVISORY ('AV.A', allActions, 'Avalanche'), # AVALANCHE WATCH ('VO.W', allActions, 'Volcano'), # VOLCANO WARNING ('AS.Y', allActions, 'AirStag'), # AIR STAGNATION ADVISORY ('SU.Y', allActions, 'HighSurf'), # HIGH SURF ADVISORY ('AF.Y', allActions, 'Ashfall'), # VOLCANIC ASHFALL ADVISORY ('LO.Y', allActions, 'Drought'), # LOW WATER ADVISORY ('TO.A', allActions, 'Convective'), # TORNADO WATCH ('SV.A', allActions, 'Convective'), # SEVERE THUNDERSTORM WATCH ]