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

949 lines
35 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.
#
# FirePhrases.py
# Methods for producing text forecast from SampleAnalysis statistics.
#
# Author: hansen
# ----------------------------------------------------------------------------
#
# SOFTWARE HISTORY
#
# Date Ticket# Engineer Description
# ------------- -------- --------- --------------------------------------------
# Feb 15, 2018 6975 randerso Fixed smokeDispersal_words to eliminate
# "excellent to excellent" phrasing
# Feb 27, 2018 7101 randerso Fixed haines_words to handle haines_dict
# with empty strings. Removed "or " from
# haines_dict strings to avoid repeated "or"
# when 2 values are present.
#
#
##
##
# This is a base file that is not intended to be overridden.
##
import ScalarPhrases
import VectorRelatedPhrases
import WxPhrases
import DiscretePhrases
class FirePhrases(ScalarPhrases.ScalarPhrases, VectorRelatedPhrases.VectorRelatedPhrases,
WxPhrases.WxPhrases, DiscretePhrases.DiscretePhrases):
def __init__(self):
ScalarPhrases.ScalarPhrases.__init__(self)
VectorRelatedPhrases.VectorRelatedPhrases.__init__(self)
WxPhrases.WxPhrases.__init__(self)
DiscretePhrases.DiscretePhrases.__init__(self)
############################################
### FIRE WEATHER PHRASES
### Sky and Weather
def includeSkyRanges_flag(self, tree, node):
# Set to 0 if you do not want ranges reported with sky phrases:
# Partly cloudy (35-40 PERCENT)
return 1
def skyWeather_byTimeRange_compoundPhrase(self):
return {
"phraseList": [
self.fireSky_phrase,
self.weather_phrase,
],
"phraseMethods": [
self.consolidateSubPhrases,
self.assembleSentences,
self.skyWeather_finishUp,
],
}
def skyWeather_finishUp(self, tree, node):
"Create a phrase for sky/weather"
words = node.get("words")
if words is None:
return
if words == "":
words = "MISSING"
node.set("descriptor", "")
node.set("indentLabel", "Sky/weather.........")
node.set("compound", 1)
return self.DONE()
def fireSky_phrase(self):
return {
"setUpMethod": self.fireSky_setUp,
"wordMethod": self.fireSky_words,
"phraseMethods": [
self.checkLocalEffects,
self.combineSky,
self.combineWords,
self.fillNulls,
self.assembleSubPhrases,
self.postProcessPhrase,
],
}
def fireSky_setUp(self, tree, node):
elementInfoList = [self.ElementInfo("Sky", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
return self.DONE()
def fireSky_words(self, tree, node):
# Report average as a worded summary, also return average
statDict = node.getStatDict()
stats = self.getStats(statDict, "Sky")
if stats is None:
return self.setWords(node, "")
avg = self.getValue(stats)
dayNight = self.getPeriod(node.getTimeRange(), 1)
words = self.sky_value(tree, node, avg, dayNight)
words = self.addSkyRange(tree, node, words, avg)
return self.setWords(node, words)
def addSkyRange(self, tree, node, words, avg):
# Add range if desired
if self.includeSkyRanges_flag(tree, node):
roundAvg = int(self.round(avg, "Nearest", 5))
if roundAvg < 5:
min = 0
else:
min = roundAvg - 5
if roundAvg >= 100:
max = 100
else:
max = roundAvg + 5
units = self.units_descriptor(tree, node, "units", "%")
words = words + " (" + repr(min) + "-" + repr(max) + units + ")"
return words
# Trends
### MinT, MaxT, MinRH, MaxRH, RH
def trend_DayOrNight_phrase(self):
return {
"setUpMethod": self.trend_DayOrNight_setUp,
"wordMethod": self.trend_DayOrNight_words,
"phraseMethods": [
self.checkLocalEffects,
self.assembleSubPhrases,
self.postProcessPhrase,
],
}
def trend_DayOrNight_setUp(self, tree, node):
dayElement, nightElement, trendElement, indent, endWithPeriod = node.get("args")
dayNight = self.getPeriod(node.getTimeRange(), 1)
if dayNight == self.DAYTIME():
elementName = dayElement
else:
elementName = nightElement
elementInfoList = [self.ElementInfo(elementName, "MinMax")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("trendElement", trendElement)
node.set("descriptor", "")
if indent == 1:
node.set("indentLabel", " 24 hr trend......")
return self.DONE()
def trend_DayOrNight_words(self, tree, node):
"Compare current analysis to previous analysis for trends"
elementName = node.get("elementName")
higher = self.phrase_descriptor(tree, node, "higher", elementName)
lower = self.phrase_descriptor(tree, node, "lower", elementName)
threshold = self.trend_threshold(tree, node, elementName, elementName)
if elementName == "MinT" or elementName == "MaxT":
units = self.units_descriptor(tree, node, "units", "degrees")
unit = self.units_descriptor(tree, node, "unit", "degree")
if elementName == "MaxRH" or elementName == "MinRH" or elementName == "RH":
units = self.units_descriptor(tree, node, "units", "%")
unit = self.units_descriptor(tree, node, "unit", "%")
trendElement = node.getAncestor("trendElement")
words, diff = self.getTrend(
tree, node, elementName, trendElement, "", units, unit, threshold,
higher, lower)
if words is not None:
if diff == 0:
words = self.phrase_descriptor(tree, node, "unchanged", elementName)
else:
words = self.phrase_descriptor(tree, node, "missing", elementName)
return self.setWords(node, words)
def getTrend(self, tree, phrase, element, trendElement, introWords, units, unit, threshold,
positiveDescriptor, negativeDescriptor):
timeRange = phrase.getTimeRange()
areaLabel = phrase.getAreaLabel()
absDiff, rawDiff = self.getTrendStats(
tree, phrase, element, timeRange, areaLabel, trendElement)
if absDiff is None:
return absDiff, rawDiff
diff = int(absDiff)
if absDiff >= threshold:
if rawDiff >= 0:
descriptor = positiveDescriptor
else:
descriptor = negativeDescriptor
if diff == 1:
units = unit
introWords = self.addSpace(introWords)
if units != "%":
units = " " + units
words = introWords + repr(diff) + units + " " + descriptor
else:
words = ""
#print "returning", words, diff
return words, diff
def getTrendStats(self, tree, phrase, element, timeRange, areaLabel, trendElement):
# NO CONVERSION DONE
# Try the trend element first
stats = tree.stats.get(trendElement, timeRange, areaLabel,
mergeMethod="Average")
#print "\ngetTrendStats"
if stats is not None:
rawDiff = int(self.getValue(stats))
absDiff = abs(rawDiff)
else:
#Use Max/Min element
curStats = tree.stats.get(element, timeRange, areaLabel,
mergeMethod="Average", statLabel="mode")
#print "curstats", curStats
if curStats is None:
return None, 0
prevTimeRange = self.adjustTimeRange(timeRange, -24)
prevStats = tree.stats.get(element, prevTimeRange, areaLabel,
mergeMethod="Average", statLabel="mode")
#print "prevstats", prevStats
if prevStats is None:
return None, 0
prevStats = self.getValue(prevStats)
curStats = self.getValue(curStats)
#print "cur, prev", element, curStats, prevStats
absDiff = self.absDiff(curStats, prevStats)
rawDiff = curStats - prevStats
#print "absDiff, rawDiff", absDiff, rawDiff
return absDiff, rawDiff
def dayOrNight_phrase(self):
return {
"setUpMethod": self.dayOrNight_setUp,
"wordMethod": self.fire_dayOrNight_words,
"phraseMethods": [
self.checkLocalEffects,
self.assembleSubPhrases,
self.postProcessPhrase,
],
}
def dayOrNight_setUp(self, tree, node):
dayElement, nightElement, indent, endWithPeriod = node.get("args")
elementName = self.dayOrNight_element(tree, node, dayElement, nightElement)
indentName = elementName + "_FireWx"
method = "MinMax"
if elementName == "RH":
dayNight = self.getPeriod(node.getTimeRange(), 1)
if dayNight == self.DAYTIME():
indentName = "MinRH_FireWx"
method = "Min"
else:
indentName = "MaxRH_FireWx"
method = "Max"
elementInfoList = [self.ElementInfo(elementName, method)]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", indentName)
return self.DONE()
def fire_dayOrNight_words(self, tree, node):
elementName = node.getAncestor("elementName")
statDict = node.getStatDict()
if elementName == "MaxT" or elementName == "MinT":
stats = self.getTempStats(tree, node)
if stats is None:
return self.setWords(node.parent, "MISSING")
words = self.getTempRangePhrase(tree, node, stats, elementName)
else: # MinRH, MaxRH or RH
stats = self.getStats(statDict, elementName)
if stats is None:
return self.setWords(node.parent, "MISSING")
connector = self.value_connector(tree, node, elementName, elementName)
min, max = self.getValue(stats, "MinMax")
if min == max:
words = repr(int(min))
else:
words = repr(int(min)) + connector + repr(int(max))
outUnits = self.element_outUnits(tree, node, elementName, elementName)
units = self.units_descriptor(tree, node, "units", outUnits)
words = words + units
return self.setWords(node, words)
### CWR
def cwr_phrase(self):
return {
"setUpMethod": self.cwr_setUp,
"wordMethod": self.cwr_words,
"phraseMethods": self.standard_phraseMethods(),
}
def cwr_setUp(self, tree, node):
try:
cwr = self._cwrParm
except:
cwr = "CWR"
elementInfoList = [self.ElementInfo(cwr, "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", "CWR.................")
return self.DONE()
def cwr_words(self, tree, node) :
"Create phrase Probability of Precipitation"
statDict = node.getStatDict()
cwr = self.getStats(statDict, "CWR")
if cwr is None:
return self.setWords(node.parent, "MISSING")
cwr = self.getValue(cwr)
threshold = self.nlValue(self.null_nlValue(
tree, node, "CWR", "CWR"), cwr)
if int(cwr) < threshold:
return self.setWords(node, "null")
else:
words = repr(int(cwr)) + " percent"
return self.setWords(node, words)
### VentRate or smoke dispersal phrase
def smokeDispersal_phrase(self):
return {
"setUpMethod": self.smokeDispersal_setUp,
"wordMethod": self.smokeDispersal_words,
"phraseMethods": self.standard_phraseMethods(),
}
def smokeDispersal_setUp(self, tree, node):
elementInfoList = [self.ElementInfo("VentRate", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", "Smoke dispersal.....")
return self.DONE()
def smokeDispersal_words(self, tree, node):
"Create phrase for Smoke Dispersal"
statDict = node.getStatDict()
stats = self.getStats(statDict, "VentRate")
if stats is None:
return self.setWords(node.parent, "MISSING")
vr1, vr2 = self.getValue(stats, "MinMax")
vr1 = int(vr1)
vr2 = int(vr2)
vrCat1 = self.smokeDispersal_valueStr(vr1)
vrCat2 = self.smokeDispersal_valueStr(vr2)
# Single Value input
if vr1 == vr2:
words = vrCat1 + " (" + repr(vr1) + " knot-ft)"
# Range
elif vrCat1 == vrCat2:
words = vrCat1 + " (" + repr(vr1) + "-" + \
repr(vr2) + " knot-ft)"
else:
words = vrCat1 + " to " + vrCat2 + " (" + repr(vr1) + "-" + \
repr(vr2) + " knot-ft)"
return self.setWords(node, words)
# SMOKE DISPERSAL CATEGORIES
def smokeDispersal_valueStr(self, value):
"Convert smoke dispersal value to corresponding category"
if value < 40000 :
return "poor"
if value >= 40000 and value < 60000:
return "fair"
if value >= 60000 and value < 100000 :
return "good"
if value >= 100000 and value < 150000 :
return "very good"
if value >= 150000 :
return "excellent"
### Fire Winds
def transportWind_phrase(self):
return {
"setUpMethod": self.transportWind_setUp,
"wordMethod": self.vector_words,
"phraseMethods": self.standard_vector_phraseMethods(),
}
def transportWind_setUp(self, tree, node):
self.wind_setUp(tree, node, gustFlag=0, element="TransWind")
node.set("descriptor", "")
node.set("indentLabel", "Transport winds.....")
return self.DONE()
def freeWind_phrase(self):
return {
"setUpMethod": self.freeWind_setUp,
"wordMethod": self.vector_words,
"phraseMethods": self.standard_vector_phraseMethods(),
}
def freeWind_setUp(self, tree, node):
self.wind_setUp(tree, node, gustFlag=0, element="FreeWind")
node.set("descriptor", "")
node.set("indentLabel", "Free winds..........")
return self.DONE()
def ridgeValleyAreas(self, tree, node):
# List of edit area names for which we want
# ridge/valley winds reported:
#
# 20-foot winds...
# Valleys/lwr slopes...
# Ridges/upr slopes....
#
# e.g.
# return ["Area1"]
#
return []
def valleyRidgeAreaNames(self, tree, node):
# These are the areas for valleys and ridges, respectively,
# to be intersected with the current edit area for
# reporting valley winds and ridge winds, respectively.
# NOTE: If you change these area names, you will also
# need to change the names in the FirePeriod "intersectAreas"
# section.
return "Valleys", "Ridges"
def fireWind_compoundPhrase(self):
return {
"phraseList": [
self.wind_summary,
self.wind_phrase,
],
"phraseMethods": [
self.consolidateSubPhrases,
self.assembleSentences,
self.fireWind_finishUp
],
}
def fireWind_finishUp(self, tree, node):
"Create a phrase for Winds"
# Empty phrase if doing ridge/valley winds
if self.currentAreaContains(
tree, self.ridgeValleyAreas(tree, node)) == 1:
return self.setWords(node, "")
words = node.get("words")
if words is None:
return
if words == "":
words = "MISSING"
node.set("descriptor", "")
node.set("indentLabel", "20-foot winds.......")
node.set("compound", 1)
return self.setWords(node, words)
def fireWind_label_phrase(self):
return {
"setUpMethod": self.fireWind_label_setUp,
"phraseMethods": [self.postProcessPhrase],
}
def fireWind_label_setUp(self, tree, node):
if self.currentAreaContains(
tree, self.ridgeValleyAreas(tree, node)) == 0:
return self.setWords(node, "")
self.setWords(node, "")
node.set("descriptor", "")
node.set("indentLabel", "20-foot winds.......")
return self.DONE()
# Valley/Ridge split set-up
def fireValleyWind_compoundPhrase(self):
return {
"phraseList": [
self.wind_summary,
self.wind_phrase,
],
"phraseMethods": [
self.fireRidgeValleyWind_setUp,
self.consolidateSubPhrases,
self.assembleSentences,
self.fireValleyWind_finishUp
],
}
def fireRidgeValleyWind_setUp(self, tree, node):
# Used for set-up of fireRidgeWind_compoundPhrase as well.
if self.currentAreaContains(
tree, self.ridgeValleyAreas(tree, node)) == 0:
return self.setWords(node, "")
# Set up intersect area to be used for the node
areaName = node.getAreaLabel()
phraseName = node.get("name")
valleys, ridges = self.valleyRidgeAreaNames(tree, node)
if phraseName.find("Valley") >= 0:
area = valleys
else:
area = ridges
intersectName = self.getIntersectName(areaName, area)
#print "setting intersect", intersectName
node.set("areaLabel", intersectName)
return self.DONE()
def fireValleyWind_finishUp(self, tree, node):
"Create a phrase for Winds"
words = node.get("words")
if words is None:
return
if words == "":
words = "MISSING"
node.set("descriptor", "")
node.set("indentLabel", " Valleys/lwr slopes...")
node.set("compound", 1)
return self.setWords(node, words)
def fireRidgeWind_compoundPhrase(self):
return {
"phraseList": [
self.wind_summary,
self.wind_phrase,
],
"phraseMethods": [
self.fireRidgeValleyWind_setUp,
self.consolidateSubPhrases,
self.assembleSentences,
self.fireRidgeWind_finishUp
],
}
def fireRidgeWind_finishUp(self, tree, node):
"Create a phrase for Winds"
words = node.get("words")
if words is None:
return
if words == "":
words = "MISSING"
node.set("descriptor", "")
node.set("indentLabel", " Ridges/upr slopes....")
node.set("compound", 1)
return self.setWords(node, words)
### Haines
def hainesDict(self):
return {
0:"very low potential for large plume dominated fire growth",
1:"very low potential for large plume dominated fire growth",
2:"very low potential for large plume dominated fire growth",
3:"very low potential for large plume dominated fire growth",
4:"low potential for large plume dominated fire growth",
5:"moderate potential for large plume dominated fire growth",
6:"high potential for large plume dominated fire growth",
7:"high potential for large plume dominated fire growth",
8:"high potential for large plume dominated fire growth",
9:"high potential for large plume dominated fire growth",
10:"high potential for large plume dominated fire growth"
}
def haines_phrase(self):
return {
"setUpMethod": self.haines_setUp,
"wordMethod": self.haines_words,
"phraseMethods": [
self.consolidatePhrase,
self.checkLocalEffects,
self.combinePhraseStats,
self.combineWords,
self.fillNulls,
self.timeDescriptorModeration,
self.assembleSubPhrases,
self.postProcessPhrase,
]
}
def haines_setUp(self, tree, node):
elementInfoList = [self.ElementInfo("Haines", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", "Haines Index........")
return self.DONE()
def haines_words(self, tree, node):
"Create phrase for Haines Index"
statDict = node.getStatDict()
stats = self.getStats(statDict, "Haines")
if stats is None:
return self.setWords(node.parent, "MISSING")
haines1, haines2 = self.getValue(stats, "MinMax")
hainesDict = self.hainesDict()
haines1 = int(haines1)
haines2 = int(haines2)
words1 = hainesDict[haines1]
words2 = hainesDict[haines2]
# Single Value input
if haines1 == haines2:
words = repr(haines1)
# Range
else:
words = repr(haines1) + " to " + repr(haines2)
if words1:
words += " or " + words1
if words2 and words2 != words1:
words += " to " + words2
elif words2:
words += " or " + words2
return self.setWords(node, words)
### Humidity
def humidityRecovery_percentage(self, tree, node):
# If the maximum humidity is greater than this percentage,
# humidity recovery will be Excellent.
return 50
def humidityRecovery_phrase(self):
return {
"setUpMethod": self.humidityRecovery_setUp,
"wordMethod": self.humidityRecovery_words,
"phraseMethods": self.standard_phraseMethods(),
}
def humidityRecovery_setUp(self, tree, node):
timeRange = node.getTimeRange()
dayNight = self.getPeriod(timeRange, 1)
if dayNight != self.NIGHTTIME():
return self.setWords(node, "")
if self._useRH:
elementName = "RH"
else:
elementName = "MaxRH"
elementInfoList = [self.ElementInfo(elementName, "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", "Humidity recovery...")
return self.DONE()
def humidityRecovery_words(self, tree, node):
"Create phrase for Humidity recovery"
if self._useRH:
elementName = "RH"
else:
elementName = "MaxRH"
statDict = node.getStatDict()
curStats = self.getStats(statDict, elementName)
if curStats is None:
return self.setWords(node.parent, "MISSING")
maxRH = self.getValue(curStats, "Max")
if maxRH > self.humidityRecovery_percentage(tree, node):
return self.setWords(node, "Excellent")
timeRange = node.getTimeRange()
prevTimeRange = self.adjustTimeRange(timeRange, -24)
prevStats = tree.stats.get(elementName, prevTimeRange, node.getAreaLabel(),
statLabel="mode", mergeMethod="Max")
if prevStats is None:
return self.setWords(node, "")
curStats = self.getValue(curStats)
prevStats = self.getValue(prevStats)
diff = curStats - prevStats
words = ""
for threshold, label in self.humidityRecovery_valueList(tree, node):
if diff <= threshold:
words = label
break
return self.setWords(node, words)
# Humidity recovery values
def humidityRecovery_valueList(self, tree, node):
"Used to convert percent difference to corresponding category"
# If you want to return different thresholds based on edit areas:
#
# editAreaNames = ["area1", "area2"]
# if self.currentAreaContains(tree, editAreaNames):
# return [
# (15, "Poor"),
# (20, "Fair"),
# (30, "Good"),
# ]
return [
(25, "Poor"),
(55, "Moderate"),
(70, "Good"),
(100, "Excellent"),
]
### LAL
## ###################################
## # General LAL Definition #
## # mainly defined for wrn 1/2 of US#
## # but still different across the #
## # country (from Dave Metze #
## ###################################
## LALs.....(L)ightning (A)ctivity (L)evels numbered 1 through 6.
## * LAL 1 - No thunderstorms.
## * LAL 2 - isolated/slight chance thunderstorms..............PoP 5-14%
## * LAL 3 - isolated/slight chance thunderstorms..............PoP 15-24%
## * LAL 4 - scattered/chance thunderstorms....................PoP 25-54%
## * LAL 5 - numerous/likely to wide/def thunderstorms.........PoP 55-100%
## * LAL 6 - Dry lightning(thunderstorms) for LAL 3 through 5..PoP 15-100%
## The number of lightning strikes is also a variable, but not sure if the
## science of meteorology is in place to forecast the actual number of
## lightning strikes, so most offices use the potential/coverage of
## thunderstorms to determine the LAL value.
def lal_phrase(self):
return {
"setUpMethod": self.lal_setUp,
"wordMethod": self.lal_words,
"phraseMethods": [
self.consolidatePhrase,
self.checkLocalEffects,
self.combinePhraseStats,
self.combineWords,
self.fillNulls,
self.timeDescriptorModeration,
self.assembleSubPhrases,
self.postProcessPhrase,
]
}
def lal_setUp(self, tree, node):
# Wait for all Wx (and other) phrases to complete
# NOTE that we are sending the areaLabel so IF you have a local
# effect set up for LAL, you must have the same local effect set up
# for weather, AND LAL and weather should be consistent in the grids.
phraseList = self.checkPhrasesDone(
tree, node, areaLabel=node.getAreaLabel(),
exceptions=[node.get('name')])
if phraseList is None:
return
# Check to see if the weather phrase changed it's resolution.
# If so, we want to match it in the LAL phrase
nodeRes = None
for phrase in phraseList:
firstElement = phrase.get("firstElement")
if firstElement is not None and firstElement.name == "Wx":
resolution = phrase.get('resolution')
if resolution is not None:
nodeRes = resolution
break
# Use resolution of Wx phrase
elementInfoList = [self.ElementInfo("LAL", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector,
resolution=nodeRes)
node.set("descriptor", "")
node.set("indentLabel", "LAL.................")
return self.DONE()
def lal_words(self, tree, node) :
"Create phrase for Lightning Activity Level"
#statDict = node.getStatDict()
#stats = self.getStats(statDict, "LAL")
# Check low pop. If low, set LAL to 1.
popThreshold = self.pop_wx_lower_threshold(tree, node)
lowPopFlag = self.lowPop_flag(tree, node, popThreshold)
if lowPopFlag == 1:
lal = 1
else:
lal = self.matchToWx(tree, node, "LAL")
if lal is None:
return self.setWords(node, "null")
if self._lightningPhrases:
words = self.lal_value(tree, node, lal)
else:
words = repr(int(lal))
return self.setWords(node, words)
def lal_value(self, tree, node, lal):
value = "No Tstms"
if lal > 1:
value = "1-8 strikes"
if lal > 2:
value = "9-15 strikes"
if lal > 3:
value = "16-25 strikes"
if lal > 4:
value = ">25 strikes"
if lal > 5:
value = "Dry lightning"
return value
def coverageLAL_value(self, coverage):
# LAL ranges that correspond to each of the weather coverages
lalValue = self.coverageLAL_table()
return lalValue[coverage]
def coverageLAL_table(self):
# LAL ranges that correspond to each of the weather coverages
return {
"<NoCov>": (1, 1),
"Iso": self.lal_2_3,
"SChc": self.lal_2_3,
"Patchy": self.lal_wx_value,
"Areas":self.lal_wx_value,
"Chc": self.lal_wx_value,
"Sct": self.lal_wx_value,
"Lkly": self.lal_wx_value,
"Num": self.lal_wx_value,
"Brf": self.lal_wx_value,
"Frq": self.lal_wx_value,
"Ocnl": self.lal_wx_value,
"Pds": self.lal_wx_value,
"Inter":self.lal_wx_value,
"Def": self.lal_wx_value,
"Wide": self.lal_wx_value,
}
def lal_2_3(self, tree, node, highKey):
pop = tree.stats.get("PoP", node.getTimeRange(), node.getAreaLabel(),
mergeMethod="Max")
if pop > 10:
if highKey.wxType() == "T" and "Dry" in highKey.attributes():
return (6, 6)
else:
return (3, 3)
else:
return (2, 2)
def lal_wx_value(self, tree, node, highKey):
# Check for Dry Thunderstorms
if highKey.wxType() == "T" and "Dry" in highKey.attributes():
return (6, 6)
coverage = highKey.coverage()
lal_dict = {
"Patchy": (2, 2),
"Areas":(4, 4),
"Chc": (4, 4),
"Sct": (4, 4),
"Lkly": (5, 5),
"Num": (5, 5),
"Brf": (5, 5),
"Frq": (5, 5),
"Ocnl": (5, 5),
"Pds": (5, 5),
"Inter":(5, 5),
"Def": (5, 5),
"Wide": (5, 5),
}
return lal_dict[coverage]
### MixHgt
def mixingHgt_phrase(self):
return {
"setUpMethod": self.mixingHgt_setUp,
"wordMethod": self.mixingHgt_words,
"phraseMethods": self.standard_phraseMethods(),
}
def mixingHgt_setUp(self, tree, node):
elementInfoList = [self.ElementInfo("MixHgt", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
node.set("descriptor", "")
node.set("indentLabel", "Mixing height.......")
return self.DONE()
def mixingHgt_words(self, tree, node):
"Create phrase for Mixing Height"
statDict = node.getStatDict()
stats = self.getStats(statDict, "MixHgt")
if stats is None:
return self.setWords(node.parent, "MISSING")
mix1, mix2 = self.getValue(stats, "MinMax")
outUnits = self.element_outUnits(tree, node, "MixHgt", "MixHgt")
mix1 = int(mix1)
mix2 = int(mix2)
threshold = self.nlValue(self.null_nlValue(
tree, node, "MixHgt", "MixHgt"), max)
if int(mix1) < threshold and int(mix2) < threshold:
return self.setWords(node, "null")
# Single Value input
if mix1 == mix2:
words = repr(mix1) + " " + outUnits + " AGL"
# Range
else:
words = repr(mix1) + "-" + repr(mix2) + " " + outUnits + " AGL"
return self.setWords(node, words)
###---------------------------------------------------------
### OPTIONAL Phrase: Contributed by Ben Moyer, LOX
### Marine Layer - taken from mixingHgt phrase methods
###---------------------------------------------------------
def marineLayer_phrase(self):
return {
"setUpMethod": self.marineLayer_setUp,
"wordMethod": self.marineLayer_words,
"phraseMethods": self.standard_phraseMethods(),
}
def marineLayer_setUp(self, tree, node):
elementInfoList = [self.ElementInfo("MarineLayer", "List")]
self.subPhraseSetUp(tree, node, elementInfoList, self.scalarConnector)
# Do not generate for desert areas
#desertArea = ["Desert"]
#if self.currentAreaContains(tree, desertArea):
# return self.DONE()
node.set("descriptor", "")
node.set("indentLabel", "Marine layer........")
return self.DONE()
def marineLayer_words(self, tree, node):
"Create phrase for Marine Layer"
statDict = node.getStatDict()
stats = self.getStats(statDict, "MarineLayer")
if stats is None:
return self.setWords(node.parent, "MISSING")
mix1, mix2 = self.getValue(stats, "MinMax")
outUnits = self.element_outUnits(tree, node, "MixHgt", "MixHgt")
mix1 = int(mix1)
mix2 = int(mix2)
# Single Value input
# Makes "0 ft asl" be returned as "none"
if mix1 == 0 and mix2 == 0:
words = "none"
elif mix1 == mix2:
words = repr(mix1) + " " + outUnits + " asl"
# Makes phrases such as "0-800 ft asl" be simply "800 ft asl"
elif mix1 == 0 and mix2 > 0:
words = repr(mix2) + " " + outUnits + " asl"
# Range
else:
words = repr(mix1) + "-" + repr(mix2) + " " + outUnits + " asl"
return self.setWords(node, words)