Change-Id: I1c8e97e4bfd55082df3770b8321f34b0e4a1f208 Former-commit-id: e9f1505c8972f7ba362b64376421755f620e0201
1256 lines
47 KiB
Python
1256 lines
47 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.
|
|
##
|
|
#
|
|
# Name:
|
|
# MosData.py
|
|
# GFS1-NHD:A6638.0000-SCRIPT;1.69
|
|
#
|
|
# Status:
|
|
# DELIVERED
|
|
#
|
|
# History:
|
|
# Revision AWIPS II NJENSEN
|
|
# Updated to work with AWIPS II pointdata interface
|
|
#
|
|
# Revision 1.69 (DELIVERED)
|
|
# Created: 19-NOV-2008 09:28:23 OBERFIEL
|
|
# Update to include NAM-MOS guidance
|
|
#
|
|
# Revision 1.68 (DELIVERED)
|
|
# Created: 29-OCT-2008 12:47:57 OBERFIEL
|
|
# Eta-MOS guidance retired. Now NAM-MOS. Labelling to
|
|
# reflect this.
|
|
#
|
|
# Revision 1.67 (DELIVERED)
|
|
# Created: 01-AUG-2008 15:44:46 OBERFIEL
|
|
# Synch'd up with changes in OB8.3.1
|
|
#
|
|
# Revision 1.66 (DELIVERED)
|
|
# Created: 11-JUN-2008 14:53:09 OBERFIEL
|
|
# Restored use of configuration setting in file.
|
|
#
|
|
# Revision 1.65 (DELIVERED)
|
|
# Created: 16-NOV-2007 12:51:40 OBERFIEL
|
|
# Extracted additional probabilistic information out of the
|
|
# netCDF file and into the .data files.
|
|
#
|
|
# Revision 1.64 (DELIVERED)
|
|
# Created: 03-OCT-2007 13:47:16 OBERFIEL
|
|
# Fixed inadvertant conversion of 9999K to F. Empty string
|
|
# returned instead.
|
|
#
|
|
# Revision 1.63 (DELIVERED)
|
|
# Created: 26-SEP-2007 13:40:23 OBERFIEL
|
|
# Fixed rounding problem when display MOS/LAMP guidance.
|
|
# Updated Issuance and Valid time update code to call
|
|
# time.time() just once.
|
|
#
|
|
# Revision 1.62 (DELIVERED)
|
|
# Created: 14-MAY-2007 10:04:49 OBERFIEL
|
|
# Removed references to the obsolete prototype XTF product.
|
|
# Allow decoder and encoder to format TAF in two different
|
|
# ways. New format will be triggered by day and time to be
|
|
# specified at a later date.
|
|
#
|
|
# Revision 1.61 (INITIALIZE)
|
|
# Updated: 18-APR-2007 12:47:21 SOLSON
|
|
# Removed CR characters from this item.
|
|
# Created: 18-APR-2007 12:46:44 SOLSON
|
|
# Removed CR characters from the previous rev of this item.
|
|
#
|
|
# Revision 1.60 (DELIVERED)
|
|
# Created: 11-DEC-2006 09:26:12 BLI
|
|
# Modified to include conditional probability for cig and vis
|
|
# in tabulated gfsmos display
|
|
#
|
|
# Revision 1.59 (DELIVERED)
|
|
# Created: 31-AUG-2006 10:29:18 BLI
|
|
# Fixed an incorrect looking-for-drizzle number for LAMP
|
|
#
|
|
# Revision 1.58 (DELIVERED)
|
|
# Created: 16-AUG-2006 11:22:54 BLI
|
|
# Removed space from empty string
|
|
#
|
|
# Revision 1.57 (DELIVERED)
|
|
# Created: 15-JUN-2006 14:55:56 BLI
|
|
# More fix on tstm time shift
|
|
#
|
|
# Revision 1.56 (DELIVERED)
|
|
# Created: 14-JUN-2006 11:43:40 BLI
|
|
# Fixed misaligned tstm best cat and probability forecasts
|
|
#
|
|
# Revision 1.55 (DELIVERED)
|
|
# Created: 13-JUN-2006 13:44:51 BLI
|
|
# Fixed for wrong wind spd units for LAMP
|
|
#
|
|
# Revision 1.54 (DELIVERED)
|
|
# Created: 08-JUN-2006 14:14:26 BLI
|
|
# Fixed yet another index outbound problem
|
|
#
|
|
# Revision 1.53 (APPROVED)
|
|
# Created: 08-JUN-2006 13:46:25 BLI
|
|
# Fixed wind speed conversion and windGust name error
|
|
#
|
|
# Revision 1.52 (APPROVED)
|
|
# Created: 06-JUN-2006 11:50:28 BLI
|
|
# Fixed a index outbound problem
|
|
#
|
|
# Revision 1.51 (DELIVERED)
|
|
# Created: 06-JUN-2006 11:45:02 BLI
|
|
# Fixed a index outbound problem
|
|
#
|
|
# Revision 1.50 (APPROVED)
|
|
# Created: 02-JUN-2006 14:24:15 BLI
|
|
# Fixed vis cates and value mismatch
|
|
#
|
|
# Revision 1.49 (DELIVERED)
|
|
# Created: 02-JUN-2006 14:09:59 BLI
|
|
# Fixed vis category mismatch
|
|
#
|
|
# Revision 1.48 (DELIVERED)
|
|
# Created: 01-JUN-2006 14:55:10 BLI
|
|
# Fixed for 2 hour tstorm
|
|
#
|
|
# Revision 1.47 (APPROVED)
|
|
# Created: 01-JUN-2006 14:39:40 BLI
|
|
# Fixed for 2-hr tstorm
|
|
#
|
|
# Revision 1.46 (APPROVED)
|
|
# Created: 01-JUN-2006 13:04:40 BLI
|
|
# Fixed for pop value range and ptype missing
|
|
#
|
|
# Revision 1.45 (DELIVERED)
|
|
# Created: 01-JUN-2006 12:50:31 BLI
|
|
# Fixed for missing ptype and pop being in 1~100.
|
|
#
|
|
# Revision 1.44 (DELIVERED)
|
|
# Created: 17-MAY-2006 11:23:58 BLI
|
|
# Fixed wind speed units
|
|
#
|
|
# Revision 1.43 (APPROVED)
|
|
# Created: 16-MAY-2006 15:24:23 BLI
|
|
# Fixed for new LAMP netcdf files
|
|
#
|
|
# Revision 1.42 (DELIVERED)
|
|
# Created: 04-MAY-2006 09:50:29 BLI
|
|
# Assigned unlimited ceiling for 'FEW' and 'SCT'
|
|
#
|
|
# Revision 1.41 (DELIVERED)
|
|
# Created: 20-APR-2006 13:14:41 BLI
|
|
# Fixed a missing '=' for TafGen and a 'TP2' error for
|
|
# MosData
|
|
#
|
|
# Revision 1.40 (DELIVERED)
|
|
# Created: 20-APR-2006 13:02:59 BLI
|
|
# Fixed missing TCP2
|
|
#
|
|
# Revision 1.39 (DELIVERED)
|
|
# Created: 19-APR-2006 15:43:46 BLI
|
|
# Merged from 3.3.
|
|
#
|
|
# Revision 1.38 (DELIVERED)
|
|
# Created: 27-MAR-2006 13:39:12 BLI
|
|
# Modifed __name__ section
|
|
#
|
|
# Revision 1.37 (DELIVERED)
|
|
# Created: 27-MAR-2006 13:26:28 BLI
|
|
# Modfied the __name__ section for command line testing
|
|
#
|
|
# Revision 1.36 (DELIVERED)
|
|
# Created: 03-MAR-2006 15:24:22 BLI
|
|
# Fixed precip intensity for both MOS andLAMP
|
|
#
|
|
# Revision 1.35 (DELIVERED)
|
|
# Created: 03-MAR-2006 14:08:01 BLI
|
|
# Added PCO,TC2,TP2 in the tabuluated LAMP
|
|
#
|
|
# Revision 1.34 (DELIVERED)
|
|
# Created: 15-FEB-2006 13:49:15 BLI
|
|
# Changed 'SZ' to 'SN'
|
|
#
|
|
# Revision 1.33 (APPROVED)
|
|
# Created: 15-FEB-2006 13:38:59 BLI
|
|
# Corrected Frz vs SN
|
|
#
|
|
# Revision 1.32 (APPROVED)
|
|
# Created: 14-FEB-2006 14:38:15 BLI
|
|
# Changed a limit for heavy snow
|
|
#
|
|
# Revision 1.31 (APPROVED)
|
|
# Created: 14-FEB-2006 13:50:46 BLI
|
|
# Changed vis limits for '-' and '+' sn and drizzle
|
|
#
|
|
# Revision 1.30 (APPROVED)
|
|
# Created: 02-FEB-2006 08:27:40 BLI
|
|
# Changed a few notation
|
|
#
|
|
# Revision 1.29 (REVIEW)
|
|
# Created: 31-JAN-2006 08:35:25 TROJAN
|
|
# Change in naming convention for MOS/LAMP data, added LAMP
|
|
# to plotting module
|
|
#
|
|
# Revision 1.28 (APPROVED)
|
|
# Created: 30-JAN-2006 11:06:04 BLI
|
|
# Added a missing c for 'OVC'
|
|
#
|
|
# Revision 1.27 (APPROVED)
|
|
# Created: 27-JAN-2006 14:54:01 BLI
|
|
# Modified to toggle on/off prob. of LAMP
|
|
#
|
|
# Revision 1.26 (APPROVED)
|
|
# Created: 25-JAN-2006 15:44:38 BLI
|
|
# Corrected a few spacing issue for LAMP report
|
|
#
|
|
# Revision 1.25 (APPROVED)
|
|
# Created: 23-JAN-2006 14:23:27 BLI
|
|
# Changed dest dir for gfslamp
|
|
#
|
|
# Revision 1.24 (APPROVED)
|
|
# Created: 23-JAN-2006 11:14:09 BLI
|
|
# One error correction
|
|
#
|
|
# Revision 1.23 (APPROVED)
|
|
# Created: 15-DEC-2005 16:30:54 BLI
|
|
# Removed an extra space to line up with the hours
|
|
#
|
|
# Revision 1.22 (APPROVED)
|
|
# Created: 13-DEC-2005 15:18:30 BLI
|
|
# Some modifications for implementing LAMP into avnfps
|
|
#
|
|
# Revision 1.21 (DELIVERED)
|
|
# Created: 06-SEP-2005 20:17:40 TROJAN
|
|
# spr 7014
|
|
#
|
|
# Revision 1.20 (DELIVERED)
|
|
# Created: 06-SEP-2005 19:09:59 TROJAN
|
|
# spr 7009
|
|
#
|
|
# Revision 1.19 (DELIVERED)
|
|
# Created: 25-JUL-2005 19:36:26 BLI
|
|
# Fix visBestCat
|
|
#
|
|
# Revision 1.18 (APPROVED)
|
|
# Created: 25-JUL-2005 14:02:26 BLI
|
|
# Corrected two typos
|
|
#
|
|
# Revision 1.17 (APPROVED)
|
|
# Created: 22-JUL-2005 19:59:52 BLI
|
|
# Corrected an error in cigBestcat and CigCat
|
|
#
|
|
# Revision 1.16 (APPROVED)
|
|
# Created: 22-JUL-2005 15:34:25 BLI
|
|
# fixed a couple typo
|
|
#
|
|
# Revision 1.15 (APPROVED)
|
|
# Created: 14-JUL-2005 16:27:09 BLI
|
|
# merged changes
|
|
#
|
|
# Revision 1.14 (APPROVED)
|
|
# Created: 12-JUL-2005 19:45:32 BLI
|
|
# correct syntax error
|
|
#
|
|
# Revision 1.13 (APPROVED)
|
|
# Created: 11-JUL-2005 20:01:07 BLI
|
|
# map cig cats to new ones for gfs/eta
|
|
#
|
|
# Revision 1.12 (REVIEW)
|
|
# Created: 07-JUL-2005 12:36:35 TROJAN
|
|
# spr 6912
|
|
#
|
|
# Revision 1.11 (DELIVERED)
|
|
# Created: 07-MAY-2005 11:36:25 OBERFIEL
|
|
# Added Item Header Block
|
|
#
|
|
# Revision 1.10 (DELIVERED)
|
|
# Created: 21-APR-2005 18:49:45 BLI
|
|
# added check for the presence of the variable in netcdf file
|
|
# before trying to fetch them
|
|
#
|
|
# Revision 1.9 (DELIVERED)
|
|
# Created: 18-APR-2005 18:55:49 BLI
|
|
# Added handler for clouds_CL etc
|
|
#
|
|
# Revision 1.8 (APPROVED)
|
|
# Created: 18-APR-2005 18:12:19 TROJAN
|
|
# stdr 917
|
|
#
|
|
# Revision 1.7 (DELIVERED)
|
|
# Created: 04-APR-2005 15:51:08 TROJAN
|
|
# spr 6775
|
|
#
|
|
# Revision 1.6 (APPROVED)
|
|
# Created: 21-MAR-2005 15:32:31 TROJAN
|
|
# spr 6733
|
|
#
|
|
# Revision 1.5 (DELIVERED)
|
|
# Created: 15-FEB-2005 18:12:21 TROJAN
|
|
# spr 6561
|
|
#
|
|
# Revision 1.4 (DELIVERED)
|
|
# Created: 30-SEP-2004 20:22:10 TROJAN
|
|
# stdr 873
|
|
#
|
|
# Revision 1.3 (APPROVED)
|
|
# Created: 01-JUL-2004 14:59:45 OBERFIEL
|
|
# Update
|
|
#
|
|
# Revision 1.2 (DELIVERED)
|
|
# Created: 08-JAN-2004 21:40:13 PCMS
|
|
# Updating for code cleanup
|
|
#
|
|
# Revision 1.1 (APPROVED)
|
|
# Created: 06-NOV-2003 16:46:01 OBERFIEL
|
|
# date and time created -2147483647/-2147483648/-2147481748
|
|
# -2147483648:-2147483648:-2147483648 by oberfiel
|
|
#
|
|
# Change Document History:
|
|
# 1:
|
|
# Change Document: GFS1-NHD_SPR_7407
|
|
# Action Date: 03-JAN-2009 09:26:51
|
|
# Relationship Type: In Response to
|
|
# Status: TEST
|
|
# Title: AvnFPS: Allow WFOs to update HDF5 climate files
|
|
#
|
|
#
|
|
import cPickle, logging, os, time
|
|
import numpy
|
|
import pupynere
|
|
import Avn, AvnLib
|
|
|
|
ToKt = 3600.0/1852.0
|
|
|
|
import NoDataException
|
|
_Logger = logging.getLogger(Avn.CATEGORY)
|
|
|
|
|
|
# note: POP6hr and SEVERE6hr are added in by the individual MOS types
|
|
PARAMETERS = ["stationId", "refTime", "forecastHr",
|
|
"ceiling_bestCat", "windSpeedInflated", "MaxWindSpeed",
|
|
"precipFreezing", "clouds_OV", "ceiling_cat1", "ceiling_cat2", "ceiling_cat3",
|
|
"ceiling_cat4", "ceiling_cat5", "ceiling_cat6", "ceiling_cat7",
|
|
"vis_cat5", "vis_cat4", "vis_cat6", "vis_cat1",
|
|
"vis_cat3", "vis_cat2", "QPF6hr_bestCat", "tstorm6hr",
|
|
"POP_bestCat", "dewpoint", "vis_bestCat",
|
|
"precipSnow", "clouds_SC", "temperature", "clouds_BK",
|
|
"clouds_CL", "precipType", "obVis_bestCat",
|
|
"clouds_bestCat", "POP6hr", "severe6hr", "csevere6hr", "POP_hour",
|
|
"windDir", 'cvis_bestCat', 'POP_hour_bestCat',
|
|
'ltg2hr', 'ltg_bestCat', 'tstorm_bestCat',
|
|
'PQPF_6hr', 'ceiling_cat8',
|
|
'c_ceiling_cat1', 'c_ceiling_cat2', 'c_ceiling_cat3', 'c_ceiling_cat4',
|
|
'c_ceiling_cat5', 'c_ceiling_cat6', 'c_ceiling_cat7', 'c_ceiling_cat8',
|
|
'c_ceiling_bestCat',
|
|
'cvis_cat1', 'cvis_cat2', 'cvis_cat3', 'cvis_cat4', 'cvis_cat5', 'cvis_cat6']
|
|
|
|
###############################################################################
|
|
# converters used to create tables
|
|
def _textKtoF(t):
|
|
if t < 330:
|
|
return '%2.0f' % ((t-273.15)*1.8 + 32.0)
|
|
return ''
|
|
|
|
def _textDD(t):
|
|
"""t is a tuple (d, f)"""
|
|
if 0 <= t[0] <= 360:
|
|
dd = t[0]
|
|
if 0.0 <= t[1] < 0.5:
|
|
dd = 0.0
|
|
return '%02d0' % int((dd+5)/10.0)
|
|
else:
|
|
return ''
|
|
|
|
def _textFF(t):
|
|
if 0.0 <= t < 70.0:
|
|
return '%02d' % int(t*ToKt+0.5)
|
|
else:
|
|
return ''
|
|
|
|
def _textGG(t):
|
|
if 0.0 <= t < 80.0:
|
|
return '%02d' % int(t*ToKt+0.5)
|
|
else:
|
|
return ''
|
|
|
|
def _textProb(t):
|
|
if 0 <= t <= 100:
|
|
return '%3.0f' % t
|
|
else:
|
|
return ''
|
|
|
|
def _textPcpType(t):
|
|
return {1: 'FZ', 2: 'SN', 3: 'RA'}.get(t, '')
|
|
|
|
def _textLampPcpType(t):
|
|
return {1: 'FZ', 2: 'SN', 3: 'RA'}.get(t, '')
|
|
|
|
def _textObv(t):
|
|
return {0: 'BL', 2: 'HZ', 3: 'FG', 4: 'N', 5: 'BR'}.get(t, '')
|
|
|
|
def _textLampObv(t):
|
|
return {4: '', 2: 'HZ', 5: 'BR', 3: 'FG', 1: 'BL'}.get(t, '')
|
|
|
|
def _textLampLtgCat(t):
|
|
return {0: 'NO', 4: 'LOW', 6: 'MED', 8: 'HIGH'}.get(t, '')
|
|
|
|
def _textCld(t):
|
|
return {0: 'SKC', 8: 'OVC', 11: 'SCT', 12: 'BKN', 13:'FEW'}.get(t, '')
|
|
|
|
def _textLampCld(t):
|
|
return {0: 'SKC', 13: 'FEW', 11: 'SCT', 12: 'BKN', 8:'OVC'}.get(t, '')
|
|
|
|
def _getCigProbs(v,element,numCategories):
|
|
try:
|
|
probs = [v[element+str(x)] for x in xrange(1,numCategories+1)]
|
|
return [min(x,100) for x in Avn.accumulate(probs)]
|
|
except KeyError:
|
|
return [0]*(numCategories-1)+[100]
|
|
|
|
def _getVisProbs(v,element,numCategories):
|
|
try:
|
|
return [v[element+str(x)] for x in xrange(1,numCategories+1)]+[100]
|
|
except KeyError:
|
|
return [0]*(numCategories-1)+[100]
|
|
|
|
###############################################################################
|
|
class _NetCDFFile:
|
|
|
|
def __init__(self):
|
|
pass
|
|
|
|
def makeWind(self, v, noToKt):
|
|
d = {}
|
|
gg=0
|
|
dd = int(v['windDir'])
|
|
if dd != v.getFillValue('windDir'):
|
|
dd = 10*((dd+5)//10)
|
|
if dd == 0:
|
|
dd = 360
|
|
d['dd'] = dd
|
|
if 'windSpeedInflated' in v:
|
|
ff = float(v['windSpeedInflated'])
|
|
FValue=v.getFillValue('windSpeedInflated')
|
|
else:
|
|
ff = float(v['windSpeed'])
|
|
FValue = v.getFillValue('windSpeed')
|
|
if ff != FValue:
|
|
if noToKt:
|
|
d['ff'] = int(ff+0.5)
|
|
else:
|
|
d['ff'] = int(ff*ToKt+0.5)
|
|
if d['ff'] == 0:
|
|
d['dd'] = 0
|
|
if 'MaxWindSpeed' in v: gg = int(v['MaxWindSpeed']*ToKt+0.5)
|
|
if 'dd' in d and 'ff' in d and 9998 > gg > 0:
|
|
d['gg'] = int(gg)
|
|
d['str'] = '%03d%02dG%02dKT' % (d['dd'], d['ff'],d['gg'])
|
|
else:
|
|
if 'dd' in d and 'ff' in d:
|
|
d['str'] = '%03d%02dKT' % (d['dd'], d['ff'])
|
|
else:
|
|
d['str'] = '??????KT'
|
|
return d
|
|
|
|
|
|
def makeObv(self, v):
|
|
t = int(v['obVis_bestCat'])
|
|
s = {0: 'BL', 2: 'HZ', 3: 'FG', 4: '', 5: 'BR'}.get(t, '')
|
|
if s:
|
|
return {'str': s}
|
|
else:
|
|
return None
|
|
|
|
def makeVsby(klass, var):
|
|
# returns mid point of category range
|
|
tmp = klass.VsbyValues.get(int(var), None)
|
|
if tmp:
|
|
return AvnLib.fixTafVsby(tmp)
|
|
else:
|
|
return None
|
|
makeVsby = classmethod(makeVsby)
|
|
|
|
def makeSky(klass, ceiling_bestCat, clouds_bestCat):
|
|
Cld = ['SKC', 'FEW', 'SCT', 'BKN', 'OVC']
|
|
Cover = {0: 0, 8: 4, 11: 2, 12: 3, 13: 1}
|
|
cig = klass.CigValues.get(int(ceiling_bestCat), None)
|
|
cover = Cover.get(int(clouds_bestCat), None)
|
|
if cover < 3: cig = Avn.UNLIMITED
|
|
if cig is not None:
|
|
if 1 <= cover <= 4:
|
|
if cig != Avn.UNLIMITED:
|
|
d = {'str': '%s%03d' % (Cld[cover], cig/100), \
|
|
'cover': cover, 'cig': cig}
|
|
else:
|
|
d = {'str': '%s%03d' % (Cld[cover], 250), \
|
|
'cover': cover, 'cig': cig}
|
|
elif cover == 0:
|
|
d = {'str': 'SKC', 'cover': 0, 'cig': Avn.UNLIMITED}
|
|
else:
|
|
return None
|
|
return d
|
|
else:
|
|
return None
|
|
makeSky = classmethod(makeSky)
|
|
|
|
def makePcp(self, v, vsby, pdc, n, fcstHrList):
|
|
PType = {11: 'FZDZ', 12: 'FZRA', 13: 'SHPL', \
|
|
21: 'DZSN', 22: 'SN', 23: 'SHSN', \
|
|
31: 'DZ', 32: 'RA', 33: 'SHRA'}
|
|
d = {}
|
|
# shift
|
|
if n & 0x01: # 3 hours
|
|
m = 1
|
|
else: # 6 hours
|
|
m = 2
|
|
#p = int(v[self.POP6hr][recno,n+m])
|
|
p = int(pdc[fcstHrList[n+m]][self.POP6hr])
|
|
if p !=v.getFillValue(self.POP6hr):
|
|
d['pop'] = p
|
|
#p = int(v['tstorm6hr'][recno,n+m])
|
|
p = int(pdc[fcstHrList[n+m]]['tstorm6hr'])
|
|
if p != v.getFillValue('tstorm6hr'):
|
|
d['pot'] = p
|
|
ptype = int(v['precipType'])
|
|
if not 1 <= ptype <= 3:
|
|
ptype = 3 # rain
|
|
pop = int(v['POP_bestCat'])
|
|
if not 1 <= pop <= 3:
|
|
pop = 2 # continuous
|
|
intensity = ''
|
|
if ptype == 2 or pop == 1: # SN or DZ
|
|
if vsby:
|
|
if vsby > 0.50:
|
|
intensity = '-'
|
|
elif vsby < 0.245:
|
|
intensity = '+'
|
|
else:
|
|
intensity = '-'
|
|
pcp = PType[10*ptype+pop]
|
|
d.update({'str': intensity+pcp, 'int': intensity})
|
|
return d
|
|
|
|
def getRecord(self, ident):
|
|
if not self._fh:
|
|
return None
|
|
try:
|
|
return self._sitedict[ident]
|
|
except KeyError:
|
|
raise Avn.AvnError('%s not in %s' % (ident, self._path))
|
|
return None
|
|
|
|
def cigBestCat(self,t):
|
|
if 0 < t < 100:
|
|
return '%3.0f' % t
|
|
else:
|
|
return ''
|
|
|
|
def visBestCat(self,t):
|
|
if 0 < t < 100:
|
|
return '%3.0f' % t
|
|
else:
|
|
return ''
|
|
|
|
def makePeriod(self, pdc, n, fcstHrList):
|
|
#v = self._fh.variables
|
|
v = pdc[fcstHrList[n]]
|
|
f, t = self._validTimeList[n:n+2]
|
|
g = {'time': {'from': f, 'to': t}}
|
|
d = self.makeWind(v, 0)
|
|
if d:
|
|
g['wind'] = d
|
|
d = self.makeVsby(v['vis_bestCat'])
|
|
if d:
|
|
g['vsby'] = d
|
|
vsby = d['value']
|
|
else:
|
|
vsby = None
|
|
d = self.makePcp(v, vsby, pdc, n, fcstHrList)
|
|
if d:
|
|
g['pcp'] = d
|
|
d = self.makeObv(v)
|
|
if d:
|
|
g['obv'] = d
|
|
d = self.makeSky(v['ceiling_bestCat'], v['clouds_bestCat'])
|
|
if d:
|
|
g['sky'] = d
|
|
# fix visibility and obstruction to vision
|
|
if 'vsby' in g and 'obv' in g and g['obv']['str'] in ['BR', 'FG']:
|
|
vsby = g['vsby']['value']
|
|
if vsby > 6.1:
|
|
g['vsby'] = {'str': '6SM', 'value': 6.0}
|
|
if vsby < 0.6:
|
|
g['obv']['str'] = 'FG'
|
|
elif vsby <= 6.1:
|
|
g['obv']['str'] = 'BR'
|
|
return g
|
|
|
|
def close(self):
|
|
try:
|
|
self._fh.close()
|
|
except:
|
|
_Logger.error('Failed to close data file')
|
|
|
|
def getFile(self, path):
|
|
try:
|
|
self._path = path
|
|
self._fh = pupynere.NetCDFFile(self._path, 'r')
|
|
self.issuetime = self._fh.variables['time'].getValue()
|
|
self._validtimes = \
|
|
self._fh.variables['validTimeList'][:self.NumData].tolist()
|
|
var = self._fh.variables['stationName']
|
|
self._sitedict = {}
|
|
for n in xrange(var.shape[0]):
|
|
ident = var[n,:].tostring().split('\x00')[0].rstrip()
|
|
self._sitedict[ident] = n
|
|
return True
|
|
except IOError:
|
|
_Logger.error('Error accessing %s', path)
|
|
return False
|
|
|
|
def makeData(self, ident, refTime=None):
|
|
# recno = self.getRecord(ident)
|
|
# if recno is None:
|
|
# return None
|
|
|
|
import ForecastPointDataRetrieve
|
|
# print 'makeData: ident (%s), selfModel(%s) refTime(%s):' % (ident, self.Model, refTime)
|
|
pdc = ForecastPointDataRetrieve.retrieve('bufrmos' + self.Model, ident, PARAMETERS, refTime=refTime)
|
|
self.NumData = min(self.NumData, len(pdc.keys()))
|
|
self.issuetime = pdc.refTime.getTime() / 1000
|
|
fcstHrList = pdc.keys()
|
|
fcstHrList.sort()
|
|
self._validTimeList = []
|
|
for f in fcstHrList:
|
|
self._validTimeList.append(self.issuetime + (f * 3600))
|
|
|
|
#
|
|
# NGMMOS. The internal ID should be four characters long.
|
|
if len(ident) == 3:
|
|
ident = 'K'+ident
|
|
|
|
d = {'itime': {'value': self.issuetime, \
|
|
'str': time.strftime('%d%H%MZ', time.gmtime(self.issuetime))}, \
|
|
'ident': {'str': ident}}
|
|
d['group'] = [self.makePeriod(pdc,n, fcstHrList) for n in range(self.NumData)]
|
|
return d
|
|
|
|
def loopAll(self, pdc, fcstHrList, key):
|
|
result = []
|
|
for f in fcstHrList:
|
|
result.append(pdc[f][key])
|
|
if len(result) == self.NumData:
|
|
break
|
|
return result
|
|
|
|
def makeReport(self, ident):
|
|
import ForecastPointDataRetrieve
|
|
pdc = ForecastPointDataRetrieve.retrieve('bufrmos' + self.Model, ident, PARAMETERS)
|
|
self.NumData = min(self.NumData, len(pdc.keys()))
|
|
self.issuetime = pdc.refTime.getTime() / 1000
|
|
fcstHrList = pdc.keys()
|
|
fcstHrList.sort()
|
|
self._validTimeList = []
|
|
count = 0;
|
|
for f in fcstHrList:
|
|
self._validTimeList.append(self.issuetime + (f * 3600))
|
|
count += 1
|
|
if count >= self.NumData:
|
|
break
|
|
|
|
rpt = ['%s %s %s' % (ident, self.Header, \
|
|
time.strftime('%x %H%M UTC', time.gmtime(self.issuetime)))]
|
|
#v = self._fh.variables
|
|
rpt.append('hour ' + ' '.join([time.strftime(' %H',
|
|
time.gmtime(t)) for t in self._validTimeList]))
|
|
if pdc.hasParam('temperature'):
|
|
t = map(_textKtoF, self.loopAll(pdc, fcstHrList, 'temperature'))
|
|
rpt.append('TMP ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('dewpoint'):
|
|
t = map(_textKtoF, self.loopAll(pdc, fcstHrList, 'dewpoint'))
|
|
rpt.append('DPT ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('windDir'):
|
|
#t = map(_textDD, zip(v['windDir'][recno,:self.NumData],
|
|
# v['windSpeedInflated'][recno,:self.NumData]))
|
|
t = map(_textDD, zip(self.loopAll(pdc, fcstHrList, 'windDir'),
|
|
self.loopAll(pdc, fcstHrList, 'windDir')))
|
|
rpt.append('WDR ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('windSpeedInflated'):
|
|
t = map(_textFF, self.loopAll(pdc, fcstHrList, 'windSpeedInflated'))
|
|
rpt.append('WSP ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('MaxWindSpeed'):
|
|
t = map(_textGG, self.loopAll(pdc, fcstHrList, 'MaxWindSpeed'))
|
|
rpt.append('WGST ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('vis_bestCat'):
|
|
t = map(self.visBestCat, self.loopAll(pdc, fcstHrList, 'vis_bestCat'))
|
|
rpt.append('VIS ' + '%+4s' * self.NumData % tuple(t))
|
|
|
|
for cat in ['vis_cat%d' % k for k in range(1, self.NumVsbyCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
|
|
if pdc.hasParam('obVis_bestCat'):
|
|
t = map(_textObv, self.loopAll(pdc, fcstHrList, 'obVis_bestCat'))
|
|
rpt.append('OBVIS ' + '%+4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_bestCat'):
|
|
t = map(_textCld, self.loopAll(pdc, fcstHrList, 'clouds_bestCat'))
|
|
rpt.append('CLD ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_CL'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_CL'))
|
|
rpt.append('PSKC ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_FW'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_FW'))
|
|
rpt.append('PFEW ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_SC'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_SC'))
|
|
rpt.append('PSCT ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_BK'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_BK'))
|
|
rpt.append('PBKN ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_OV'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_OV'))
|
|
rpt.append('POVC ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('ceiling_bestCat'):
|
|
t = map(self.cigBestCat, self.loopAll(pdc, fcstHrList, 'ceiling_bestCat'))
|
|
rpt.append('CIG ' + '%-4s' * self.NumData % tuple(t))
|
|
for cat in ['ceiling_cat%d' % k for k in \
|
|
range(1, self.NumCigCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
if pdc.hasParam('precipType'):
|
|
t = map(_textPcpType, self.loopAll(pdc, fcstHrList, 'precipType'))
|
|
rpt.append('PTYPE ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam(self.POP6hr):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, self.POP6hr))
|
|
rpt.append('POP06 ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('QPF6hr_bestCat'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'QPF6hr_bestCat'))
|
|
rpt.append('QPF06 ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('tstorm6hr'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'tstorm6hr'))
|
|
rpt.append('TS06 ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam(self.SEVERE6hr):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, self.SEVERE6hr))
|
|
rpt.append('STS06 ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('precipFreezing'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'precipFreezing'))
|
|
rpt.append('POZ ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('precipSnow'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'precipSnow'))
|
|
rpt.append('POS ' + '%-4s' * self.NumData % tuple(t))
|
|
rpt.append('')
|
|
return rpt
|
|
|
|
###############################################################################
|
|
class _AvnNetCDFFile(_NetCDFFile):
|
|
"""AVN MOS NetCDF file"""
|
|
NumData = 15 # 42 hours
|
|
NumVsbyCat = 7
|
|
NumCigCat = 7
|
|
POP6hr = 'PQPF_6hr' # to avoid repeating code
|
|
SEVERE6hr='severe6hr'
|
|
VsbyValues = {1: 0.25, 2: 0.5, 3: 0.75, 4: 2.0, 5: 4.0, 6: 6.0, 7: 99.0}
|
|
CigValues = {1: 100, 2: 400, 3: 700, 4: 2000, 5: 5000, 6: 10000, 7: 25000}
|
|
Header = 'AVN MOS Guidance'
|
|
Model = 'AVN'
|
|
|
|
###############################################################################
|
|
class _NgmNetCDFFile(_NetCDFFile):
|
|
"""NGM MOS NetCDF file"""
|
|
NumData = 15 # 42 hours
|
|
NumVsbyCat = 5
|
|
NumCigCat = 7
|
|
POP6hr = 'POP6hr' # to avoid repeating code
|
|
SEVERE6hr='severe6hr'
|
|
VsbyValues = {1: 0.25, 2: 0.75, 3: 2.0, 4: 4.0, 5: 99.0}
|
|
CigValues = {1: 100, 2: 400, 3: 700, 4: 2000, 5: 5000, 6: 10000, 7: 25000}
|
|
Header = 'NGM MOS Guidance'
|
|
Model = 'NGM'
|
|
|
|
###############################################################################
|
|
class _GfsNetCDFFile(_NetCDFFile):
|
|
"""GFS MOS NetCDF file"""
|
|
NumData = 15 # 42 hours
|
|
NumVsbyCat = 7
|
|
NumCigCat = 8
|
|
POP6hr = 'PQPF_6hr' # to avoid repeating code
|
|
SEVERE6hr='csevere6hr'
|
|
VsbyValues = {8: 0.25, 9: 0.5, 10: 1.5, 11: 2.5, 5: 4.0, 6: 5.5, 7: 10.0}
|
|
CigValues = {1:100, 2:400, 3:700, 8:1500, 9:2500, 5:5000, 6:10000, 7:25000}
|
|
Header = 'GFS MOS Guidance'
|
|
Model = 'GFS'
|
|
|
|
def cigBestCat(self,t):
|
|
covt={1:1, 2:2, 3:3, 8:4, 9:5, 5:6, 6:7, 7:8}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
def visBestCat(self,t):
|
|
covt={8:1, 9:2, 10:3, 11:4, 5:5, 6:6, 7:7}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
###############################################################################
|
|
class _EtaNetCDFFile(_NetCDFFile):
|
|
"""NAM MOS NetCDF file"""
|
|
NumData = 15 # 42 hours
|
|
NumVsbyCat = 7
|
|
NumCigCat = 8
|
|
POP6hr = 'PQPF_6hr' # to avoid repeating code
|
|
SEVERE6hr='csevere6hr'
|
|
VsbyValues = {8: 0.25, 9: 0.5, 10: 1.5, 11: 2.5, 5: 4.0, 6: 5.5, 7: 10.0}
|
|
CigValues = {1:100, 2:400, 3:700, 8:1500, 9:2500, 5:5000, 6:10000, 7:25000}
|
|
Header = 'NAM MOS Guidance'
|
|
Model = 'ETA'
|
|
|
|
def cigBestCat(self,t):
|
|
covt={1:1, 2:2, 3:3, 8:4, 9:5, 5:6, 6:7, 7:8}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
def visBestCat(self,t):
|
|
covt={8:1, 9:2, 10:3, 11:4, 5:5, 6:6, 7:7}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
###############################################################################
|
|
class _GfsLampNetCDFFile(_NetCDFFile):
|
|
"""GFS LAMP NetCDF file"""
|
|
NumData = 25 # 25 forecast hours
|
|
NumVsbyCat = 6
|
|
NumCigCat = 8
|
|
POP6hr = 'POP_hour' # to avoid repeating code
|
|
SEVERE6hr = ''
|
|
VsbyValues = {8: 0.25, 9: 0.5, 10: 1.5, 11: 2.5, 5: 4.0, 6: 6, 7: 10.0}
|
|
CigValues = {1:100, 2:300, 3:700, 8:1500, 9:2500, 5:5000, 6:10000, 7:25000}
|
|
Header = 'GFS LAMP Guidance'
|
|
Model = 'LAMP'
|
|
|
|
def cigBestCat(self,t):
|
|
covt={1:1, 2:2, 3:3, 8:4, 9:5, 5:6, 6:7, 7:8}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
def visBestCat(self,t):
|
|
covt={8:1, 9:2, 10:3, 11:4, 5:5, 6:6, 7:7}
|
|
try:
|
|
return '%3.0f' % covt[int(t+0.1)]
|
|
except:
|
|
return ''
|
|
|
|
def makeObv(self, v):
|
|
t = int(v['obVis_bestCat'])
|
|
s = {4: '', 2: 'HZ', 5: 'BR', 3: 'FG', 1: 'BL'}.get(t, '')
|
|
if s:
|
|
return {'str': s}
|
|
else:
|
|
return None
|
|
|
|
def makePcp(self, v, vsby, pdc, n, fcstHrList):
|
|
PType = {13: 'SHPL', 11: 'FZDZ', 12: 'FZRA', \
|
|
23: 'SHSN', 21: 'DZSN', 22: 'SN', \
|
|
33: 'SHRA', 31: 'DZ', 32: 'RA'}
|
|
d = {}
|
|
p = v['POP_hour']
|
|
if p != v.getFillValue('POP_hour'):
|
|
d['pop'] = int(p)
|
|
p = int(v['POP_hour_bestCat'])
|
|
if p != v.getFillValue('POP_hour_bestCat'):
|
|
d['pcat'] = p
|
|
|
|
#tstm has overlapped 2-hour forecasts in the first five hours,then 2 hour
|
|
if n < self.NumData-1:
|
|
#p = v['ltg2hr'][recno,n+1]
|
|
p = pdc[fcstHrList[n+1]]['ltg2hr']
|
|
if p == v.getFillValue('ltg2hr') and n < self.NumData-2:
|
|
try:
|
|
#p = v['ltg2hr'][recno,n+2]
|
|
p = pdc[fcstHrList[n+2]]['ltg2hr']
|
|
except:
|
|
p = v.getFillValue('ltg2hr')
|
|
else:
|
|
p = v.getFillValue('ltg2hr')
|
|
if p != v.getFillValue('ltg2hr'):
|
|
d['pot'] = int(p)
|
|
|
|
if n < self.NumData-1:
|
|
#p = int(v['ltg_bestCat'][recno,n+1])
|
|
p = int(pdc[fcstHrList[n+1]]['ltg_bestCat'])
|
|
if p == v.getFillValue('ltg_bestCat') and n < self.NumData-2:
|
|
try:
|
|
#p = int(v['ltg_bestCat'][recno,n+2])
|
|
p = int(pdc[fcstHrList[n+2]]['ltg_bestCat'])
|
|
except:
|
|
p = v.getFillValue('ltg_bestCat')
|
|
else:
|
|
p = v.getFillValue('ltg_bestCat')
|
|
|
|
if p != v.getFillValue('ltg_bestCat'):
|
|
d['tcat'] = p
|
|
ptype = int(v['precipType'])
|
|
#if ptype is missing, it's rain
|
|
if ptype == v.getFillValue('precipType'):
|
|
ptype = 3 # rain
|
|
pchar = int(v['POP_bestCat'])
|
|
if pchar == v.getFillValue('POP_bestCat'):
|
|
pchar = 2
|
|
intensity = ''
|
|
if ptype == 2 or pchar == 1: # SN or DZ
|
|
if vsby:
|
|
if vsby < 0.245:
|
|
intensity = '+'
|
|
elif vsby > 0.50:
|
|
intensity = '-'
|
|
else:
|
|
intensity = '-'
|
|
pcp = PType[ptype*10+pchar]
|
|
d.update({'str': intensity+pcp, 'int': intensity})
|
|
return d
|
|
|
|
def makeSky(klass, ceiling_bestCat, clouds_bestCat):
|
|
Cld = {0:'SKC', 13:'FEW', 11:'SCT', 12:'BKN', 8:'OVC'}
|
|
cig = klass.CigValues.get(int(ceiling_bestCat), None)
|
|
cover = int(clouds_bestCat)
|
|
#if sky cover is not BKN or OVC, set cig to unlimited.
|
|
if cover in [0, 13, 11] : cig = Avn.UNLIMITED
|
|
|
|
if cig is not None:
|
|
if cover == 0:
|
|
d = {'str': 'SKC', 'cover': 0, 'cig': Avn.UNLIMITED}
|
|
elif cover in [0,13,11,12,8]:
|
|
if cig != Avn.UNLIMITED:
|
|
d = {'str': '%s%03d' % (Cld[cover], cig/100), \
|
|
'cover': cover, 'cig': cig}
|
|
else:
|
|
d = {'str': '%s%03d' % (Cld[cover], 250), \
|
|
'cover': cover, 'cig': cig}
|
|
else:
|
|
return None
|
|
return d
|
|
else:
|
|
return None
|
|
makeSky = classmethod(makeSky)
|
|
|
|
def makePeriod(self, pdc, n, fcstHrList):
|
|
#v = self._fh.variables
|
|
v = pdc[fcstHrList[n]]
|
|
try:
|
|
#f, t = v['validTimeList'][n:n+2]
|
|
f, t = self._validTimeList[n:n+2]
|
|
except ValueError: #LAMP only has 25 projections, so need to consider running out of pairs
|
|
#f, t = v['validTimeList'][n],v['validTimeList'][n]+3600
|
|
f,t = self._validTimeList[n],self._validTimeList[n]+3600
|
|
|
|
g = {'time': {'from': f, 'to': t}}
|
|
d = self.makeWind(v, 0)
|
|
if d:
|
|
g['wind'] = d
|
|
|
|
d = self.makeVsby(v['vis_bestCat'])
|
|
if d:
|
|
g['vsby'] = d
|
|
vsby = d['value']
|
|
else:
|
|
vsby = None
|
|
|
|
d = self.makeVsby(v['cvis_bestCat'])
|
|
if d:
|
|
g['cvsby'] = d
|
|
cvsby = d['value']
|
|
else:
|
|
cvsby = None
|
|
|
|
if v['POP_hour']*100 > 40:
|
|
vsby=cvsby
|
|
|
|
d = self.makePcp(v, vsby, pdc, n, fcstHrList)
|
|
if d:
|
|
g['pcp'] = d
|
|
|
|
d = self.makeObv(v)
|
|
if d:
|
|
g['obv'] = d
|
|
#cobv is the same as obv until 'FG' and 'BR' is switched based vis
|
|
g['cobv'] = d
|
|
|
|
d = self.makeSky(v['ceiling_bestCat'], v['clouds_bestCat'])
|
|
if d:
|
|
g['sky'] = d
|
|
|
|
try:
|
|
d = self.makeSky(v['c_ceiling_bestCat'], v['clouds_bestCat'])
|
|
if d:
|
|
g['csky'] = d
|
|
except:
|
|
pass
|
|
|
|
# fix visibility and obstruction to vision
|
|
if 'vsby' in g and 'obv' in g and g['obv']['str'] in ['BR', 'FG']:
|
|
vsby = g['vsby']['value']
|
|
if vsby > 6.1:
|
|
g['vsby'] = {'str': '6SM', 'value': 6.0}
|
|
if vsby < 0.6:
|
|
g['obv']['str'] = 'FG'
|
|
elif vsby <= 6.1:
|
|
g['obv']['str'] = 'BR'
|
|
|
|
# fix conditional visibility and obstruction to vision
|
|
if 'cvsby' in g and 'obv' in g and g['obv']['str'] in ['BR', 'FG']:
|
|
vsby = g['cvsby']['value']
|
|
if vsby > 6.1:
|
|
g['cvsby'] = {'str': '6SM', 'value': 6.0}
|
|
if vsby < 0.6:
|
|
g['cobv']['str'] = 'FG'
|
|
elif vsby <= 6.1:
|
|
g['cobv']['str'] = 'BR'
|
|
#
|
|
# include the probabilities
|
|
# Look ahead for the 6hr QPF POP
|
|
#
|
|
g['pop6hr'] = -1
|
|
try:
|
|
for i in xrange(n,25):
|
|
#if v['PQPF_6hr'][recno,i] < 100:
|
|
if pdc[fcstHrList[i]]['PQPF_6hr'] < 100:
|
|
#g['pop6hr'] = v['PQPF_6hr'][recno,i]
|
|
g['pop6hr'] = pdc[fcstHrList[i]]['PQPF_6hr']
|
|
break
|
|
except KeyError:
|
|
pass
|
|
#
|
|
# Probability of ceiling categories including best category
|
|
g['cprob'] = _getCigProbs(v,'ceiling_cat',8)
|
|
g['ccprob'] = _getCigProbs(v,'c_ceiling_cat',8)
|
|
try:
|
|
g['cig_bestCat'] = int(self.cigBestCat(v['ceiling_bestCat']))
|
|
g['ccig_bestCat'] =int(self.cigBestCat(v['c_ceiling_bestCat']))
|
|
except ValueError:
|
|
pass
|
|
#
|
|
# Probability of visibility categories including best category
|
|
g['vprob'] = _getVisProbs(v,'vis_cat',6)
|
|
g['cvprob'] = _getVisProbs(v,'cvis_cat',6)
|
|
try:
|
|
g['vis_bestCat'] = int(self.visBestCat(v['vis_bestCat']))
|
|
g['cvis_bestCat'] = int(self.visBestCat(v['cvis_bestCat']))
|
|
except ValueError:
|
|
pass
|
|
|
|
return g
|
|
|
|
def makeReport(self, ident):
|
|
import ForecastPointDataRetrieve
|
|
pdc = ForecastPointDataRetrieve.retrieve('bufrmos' + self.Model, ident, PARAMETERS)
|
|
self.NumData = min(self.NumData, len(pdc.keys()))
|
|
self.issuetime = pdc.refTime.getTime() / 1000
|
|
fcstHrList = pdc.keys()
|
|
fcstHrList.sort()
|
|
self._validTimeList = []
|
|
count = 0
|
|
for f in fcstHrList:
|
|
self._validTimeList.append(self.issuetime + (f * 3600))
|
|
count += 1
|
|
if count >= self.NumData:
|
|
break
|
|
|
|
rpt = ['%s %s %s' % (ident, self.Header, \
|
|
time.strftime('%x %H%M UTC', time.gmtime(self.issuetime)))]
|
|
rpt.append('hour ' + ' '.join([time.strftime(' %H',
|
|
time.gmtime(t)) for t in self._validTimeList]))
|
|
if pdc.hasParam('temperature'):
|
|
t = map(_textKtoF, self.loopAll(pdc, fcstHrList, 'temperature'))
|
|
rpt.append('TMP ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('dewpoint'):
|
|
t = map(_textKtoF, self.loopAll(pdc, fcstHrList, 'dewpoint'))
|
|
rpt.append('DPT ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('windDir'):
|
|
#if 'windDir' in v:
|
|
#t = map(_textDD, zip(v['windDir'][recno,:self.NumData],
|
|
# v['windDir'][recno,:self.NumData]))
|
|
t = map(_textDD, zip(self.loopAll(pdc, fcstHrList, 'windDir'),
|
|
self.loopAll(pdc, fcstHrList, 'windDir')))
|
|
rpt.append('WDR ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('windSpeedInflated'):
|
|
t = map(_textFF, self.loopAll(pdc, fcstHrList, 'windSpeedInflated'))
|
|
rpt.append('WSP ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('MaxWindSpeed'):
|
|
t = map(_textGG, self.loopAll(pdc, fcstHrList, 'MaxWindSpeed'))
|
|
rpt.append('WGST ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('vis_bestCat'):
|
|
t = map(self.visBestCat, self.loopAll(pdc, fcstHrList, 'vis_bestCat'))
|
|
rpt.append('VIS ' + '%+4s' * self.NumData % tuple(t))
|
|
for cat in ['vis_cat%d' % k for k in range(1, self.NumVsbyCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
if pdc.hasParam('cvis_bestCat'):
|
|
t = map(self.visBestCat, self.loopAll(pdc, fcstHrList, 'cvis_bestCat'))
|
|
rpt.append('CVIS ' + '%+4s' * self.NumData % tuple(t))
|
|
for cat in ['cvis_cat%d' % k for k in range(1, self.NumVsbyCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
if pdc.hasParam('obVis_bestCat'):
|
|
t = map(_textLampObv, self.loopAll(pdc, fcstHrList, 'obVis_bestCat'))
|
|
rpt.append('OBVIS ' + '%+4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_bestCat'):
|
|
t = map(_textLampCld, self.loopAll(pdc, fcstHrList, 'clouds_bestCat'))
|
|
rpt.append('CLD ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_CL'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_CL'))
|
|
rpt.append('PSKC ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_FW'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_FW'))
|
|
rpt.append('PFEW ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_SC'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_SC'))
|
|
rpt.append('PSCT ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_BK'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_BK'))
|
|
rpt.append('PBKN ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('clouds_OV'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'clouds_OV'))
|
|
rpt.append('POVC ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('ceiling_bestCat'):
|
|
t = map(self.cigBestCat, self.loopAll(pdc, fcstHrList, 'ceiling_bestCat'))
|
|
rpt.append('CIG ' + '%-4s' * self.NumData % tuple(t))
|
|
for cat in ['ceiling_cat%d' % k for k in \
|
|
range(1, self.NumCigCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
if pdc.hasParam('c_ceiling_bestCat'):
|
|
t = map(self.cigBestCat, self.loopAll(pdc, fcstHrList, 'c_ceiling_bestCat'))
|
|
rpt.append('CCIG ' + '%-4s' * self.NumData % tuple(t))
|
|
for cat in ['c_ceiling_cat%d' % k for k in \
|
|
range(1, self.NumCigCat+1)]:
|
|
if pdc.hasParam(cat):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, cat))
|
|
rpt.append(('%s ' + '%-4s' * self.NumData) % \
|
|
tuple([cat[-4:]] + t))
|
|
if pdc.hasParam('precipType'):
|
|
t = map(_textLampPcpType, self.loopAll(pdc, fcstHrList, 'precipType'))
|
|
rpt.append('PTYPE ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('precipSnow'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'precipSnow'))
|
|
rpt.append('POS ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('precipFreezing'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'precipFreezing'))
|
|
rpt.append('POZ ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('POP_hour'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'POP_hour'))
|
|
rpt.append('PPO ' + '%-4s' * self.NumData % tuple(t))
|
|
if pdc.hasParam('POP_hour_bestCat'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'POP_hour_bestCat'))
|
|
rpt.append('PCO ' + '%-4s' * self.NumData % tuple(t))
|
|
|
|
useOldData=True
|
|
if pdc.hasParam('ltg_bestCat'):
|
|
rawValues = self.loopAll(pdc, fcstHrList, 'ltg_bestCat')
|
|
unique = set(rawValues)
|
|
useOldData = bool(len(unique) == 1 and -9999 in unique)
|
|
if pdc.hasParam('ltg2hr'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'ltg2hr'))
|
|
rowHeader = 'TP2 ' if useOldData else 'LTG2 '
|
|
rpt.append(rowHeader + '%-4s' * self.NumData % tuple(t))
|
|
if not useOldData and pdc.hasParam('ltg_bestCat'):
|
|
t = map(_textLampLtgCat, self.loopAll(pdc, fcstHrList, 'ltg_bestCat'))
|
|
rpt.append('LTGC2 ' + '%+4s' * self.NumData % tuple(t))
|
|
elif useOldData and pdc.hasParam('tstorm_bestCat'):
|
|
t = map(_textProb, self.loopAll(pdc, fcstHrList, 'tstorm_bestCat'))
|
|
rpt.append('TC2 ' + '%-4s' * self.NumData % tuple(t))
|
|
rpt.append('')
|
|
return rpt
|
|
|
|
|
|
###############################################################################
|
|
def _cleanup(path, nhours):
|
|
tstamp = Avn.time2string(time.time()-nhours*3600.0)
|
|
for f in os.listdir(path):
|
|
if f[:10] < tstamp:
|
|
fname = os.path.join(path, f)
|
|
try:
|
|
os.unlink(fname)
|
|
except OSError, e:
|
|
_Logger.exception('Cannot remove %s', fname)
|
|
|
|
###############################################################################
|
|
def retrieve(model, idlist, includeReport, refTime=None):
|
|
if model == 'avnmos':
|
|
nc = _AvnNetCDFFile()
|
|
elif model == 'ngmmos':
|
|
nc = _NgmNetCDFFile()
|
|
elif model == 'gfsmos':
|
|
nc = _GfsNetCDFFile()
|
|
elif model == 'etamos':
|
|
nc = _EtaNetCDFFile()
|
|
elif model == 'nammos':
|
|
nc = _EtaNetCDFFile()
|
|
elif model == 'gfslamp':
|
|
nc = _GfsLampNetCDFFile()
|
|
else:
|
|
raise Avn.AvnError('Invalid model %s' % model)
|
|
ids = []
|
|
for ident in idlist:
|
|
try:
|
|
rpt = None
|
|
data = None
|
|
if includeReport:
|
|
rpt = nc.makeReport(ident) # rpt is table view
|
|
data = nc.makeData(ident, refTime=refTime)
|
|
ids.append(Avn.Bunch(data=data, rpt=rpt))
|
|
# print 'Retrieved %s data for %s at refTime %s' % (model, ident, refTime)
|
|
_Logger.info('Retrieved %s data for %s', model, ident)
|
|
except Avn.AvnError, e:
|
|
_Logger.error(str(e))
|
|
except NoDataException.NoDataException, e:
|
|
msg = [str(e)]
|
|
ids.append(Avn.Bunch(data=msg, rpt=msg))
|
|
except Exception, e:
|
|
_Logger.exception(str(e))
|
|
return ids
|
|
|
|
############################################################################
|
|
if __name__ == '__main__':
|
|
import pprint, os,sys
|
|
|
|
path = '/data/fxa/point/gfslamp/netcdf/%s' % sys.argv[1]
|
|
nc = _GfsLampNetCDFFile()
|
|
if nc.getFile(path):
|
|
pp=pprint.PrettyPrinter(indent=2)
|
|
pp.pprint(nc.makeData(sys.argv[2]))
|
|
else:
|
|
print 'File not found'
|
|
|