diff --git a/grib2io/_grib2io.py b/grib2io/_grib2io.py index 8ef11f5..cc6b2db 100644 --- a/grib2io/_grib2io.py +++ b/grib2io/_grib2io.py @@ -650,6 +650,7 @@ def _isNDFD(self): _lldivisor: float = field(init=False,repr=False,default=templates.LLDivisor()) _xydivisor: float = field(init=False,repr=False,default=templates.XYDivisor()) shapeOfEarth: templates.Grib2Metadata = field(init=False,repr=False,default=templates.ShapeOfEarth()) + earthShape: str = field(init=False,repr=False,default=templates.EarthShape()) earthRadius: float = field(init=False,repr=False,default=templates.EarthRadius()) earthMajorAxis: float = field(init=False,repr=False,default=templates.EarthMajorAxis()) earthMinorAxis: float = field(init=False,repr=False,default=templates.EarthMinorAxis()) diff --git a/grib2io/tables/__init__.py b/grib2io/tables/__init__.py index 44e1e0a..e5ef0ae 100644 --- a/grib2io/tables/__init__.py +++ b/grib2io/tables/__init__.py @@ -1,6 +1,8 @@ """ Functions for retreiving data from NCEP GRIB2 Tables. """ +#from functools import cache # USE WHEN Python 3.9+ only +from functools import lru_cache from .section0 import * from .section1 import * @@ -10,6 +12,7 @@ from .section6 import * from .originating_centers import * +GRIB2_DISCIPLINES = [0, 1, 2, 3, 4, 10, 20] def get_table(table, expand=False): """ @@ -17,7 +20,6 @@ def get_table(table, expand=False): Parameters ---------- - **`table`**: Code table number (e.g. '1.0'). NOTE: Code table '4.1' requires a 3rd value representing the product discipline (e.g. '4.1.0'). @@ -25,7 +27,6 @@ def get_table(table, expand=False): Returns ------- - **`dict`** """ if len(table) == 3 and table == '4.1': @@ -55,15 +56,14 @@ def get_value_from_table(value, table, expand=False): Parameters ---------- - **`value`**: `int` or `str` code table value. **`table`**: `str` code table number. **`expand`**: If `True`, expand output dictionary where keys are a range. + Returns ------- - Table value or `None` if not found. """ try: @@ -87,7 +87,6 @@ def get_varinfo_from_table(discipline,parmcat,parmnum,isNDFD=False): Parameters ---------- - **`discipline`**: `int` or `str` of Discipline code value of a GRIB2 message. **`parmcat`**: `int` or `str` of Parameter Category value of a GRIB2 message. @@ -99,7 +98,6 @@ def get_varinfo_from_table(discipline,parmcat,parmnum,isNDFD=False): Returns ------- - **`list`**: containing variable information. "Unknown" is given for item of information if variable is not found. - list[0] = full name @@ -124,6 +122,84 @@ def get_varinfo_from_table(discipline,parmcat,parmnum,isNDFD=False): return ['Unknown','Unknown','Unknown'] +#@cache# USE WHEN Python 3.9+ only +@lru_cache(maxsize=None) +def get_shortnames(discipline=None, parmcat=None, parmnum=None, isNDFD=False): + """ + Returns a list of variable shortNames given GRIB2 discipline, parameter + category, and parameter number. If all 3 args are None, then shortNames + from all disciplines, parameter categories, and numbers will be returned. + + Parameters + ---------- + **`discipline : int`** GRIB2 discipline code value. + + **`parmcat : int`** GRIB2 parameter category value. + + **`parmnum`**: `int` or `str` of Parameter Number value of a GRIB2 message. + + Returns + ------- + **`list`** of GRIB2 shortNames. + """ + shortnames = list() + if discipline is None: + discipline = GRIB2_DISCIPLINES + else: + discipline = [discipline] + if parmcat is None: + parmcat = list() + for d in discipline: + parmcat += list(get_table(f'4.1.{d}').keys()) + else: + parmcat = [parmcat] + if parmnum is None: + parmnum = list(range(256)) + else: + parmnum = [parmnum] + for d in discipline: + + for pc in parmcat: + for pn in parmnum: + shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2]) + + shortnames = sorted(set(shortnames)) + try: + shortnames.remove('unknown') + shortnames.remove('Unknown') + except(ValueError): + pass + return shortnames + + +#@cache# USE WHEN Python 3.9+ only +@lru_cache(maxsize=None) +def get_metadata_from_shortname(shortname): + """ + Provide GRIB2 variable metadata attributes given a GRIB2 shortName. + + Parameters + ---------- + **`shortname : str`** GRIB2 variable shortName. + + Returns + ------- + **`list`** of dictionary items where each dictionary items contains the variable + metadata key:value pairs. **NOTE:** Some variable shortNames will exist in multiple + parameter category/number tables according to the GRIB2 discipline. + """ + metadata = [] + for d in GRIB2_DISCIPLINES: + parmcat = list(get_table(f'4.1.{d}').keys()) + for pc in parmcat: + for pn in range(256): + varinfo = get_varinfo_from_table(d,pc,pn,False) + if shortname == varinfo[2]: + metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn, + fullName=varinfo[0],units=varinfo[1])) + return metadata + + def get_wgrib2_level_string(pdtn,pdt): """ Return a string that describes the level or layer of the GRIB2 message. The @@ -136,14 +212,12 @@ def get_wgrib2_level_string(pdtn,pdt): Parameters ---------- - **`pdtn`**: GRIB2 Product Definition Template Number **`pdt`**: sequence containing GRIB2 Product Definition Template (Section 4). Returns ------- - **`str`**: wgrib2-formatted level/layer string. """ if pdtn == 48: diff --git a/grib2io/tables/section3.py b/grib2io/tables/section3.py index 8c9b196..836ab6d 100644 --- a/grib2io/tables/section3.py +++ b/grib2io/tables/section3.py @@ -95,16 +95,16 @@ '255':'Missing', } -earth_params = { +table_earth_params = { '0':{'shape':'spherical','radius':6367470.0}, '1':{'shape':'spherical','radius':None}, '2':{'shape':'oblateSpheriod','major_axis':6378160.0,'minor_axis':6356775.0,'flattening':1.0/297.0}, '3':{'shape':'oblateSpheriod','major_axis':None,'minor_axis':None,'flattening':None}, '4':{'shape':'oblateSpheriod','major_axis':6378137.0,'minor_axis':6356752.314,'flattening':1.0/298.257222101}, -'5':{'shape':'oblateSpheriod','major_axis':6378137.0,'minor_axis':6356752.3142,'flattening':1.0/298.257223563}, +'5':{'shape':'ellipsoid','major_axis':6378137.0,'minor_axis':6356752.3142,'flattening':1.0/298.257222101}, '6':{'shape':'spherical','radius':6371229.0}, '7':{'shape':'oblateSpheriod','major_axis':None,'minor_axis':None,'flattening':None}, '8':{'shape':'spherical','radius':6371200.0}, } for i in range(9,256): - earth_params[str(i)] = {'shape':'unknown','radius':None} + table_earth_params[str(i)] = {'shape':'unknown','radius':None} diff --git a/grib2io/tables/section4.py b/grib2io/tables/section4.py index efb9f3c..1234860 100644 --- a/grib2io/tables/section4.py +++ b/grib2io/tables/section4.py @@ -190,7 +190,14 @@ '103':'Analysis or forecast at a horizontal level or in a horizontal layer at a point in time for waves selected by period range (see Template 4.103)', '104':'Individual ensemble forecast, control and perturbed, at a horizontal level or in a horizontal layer at a point in time for waves selected by period range (see Template 4.104)', '105':'Anomalies, significance and other derived products from an analysis or forecast in relation to a reference period at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval (see Template 4.105)', -'99-253':'Reserved', +'106':'Anomalies, significance and other derived products from an individual ensemble forecast, control and perturbed in relation to a reference period at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval (see Template 4.106)', +'107':'Anomalies, significance and other derived products from derived forecasts based on all ensemble members in relation to a reference period at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval (see Template 4.107)', +'108':'Analysis or forecast at a horizontal level or in a horizontal layer at a point in time for generic optical products (see Template 4.108)', +'109':'Individual ensemble forecast, control and perturbed, at a horizontal level or in a horizontal layer at a point in time for generic optical products (see Template 4.109)', +'110':'Average, accumulation, extreme values or other statistically processed values at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval for generic optical products (see Template 4.110)', +'111':'Individual ensemble forecast, control and perturbed, at a horizontal level or in a horizontal layer, in a continuous or non-continuous interval for generic optical products (see Template 4.111)', +'112':'Anomalies, significance and other derived products as probability forecasts in relation to a reference period at a horizontal level or in a horizontal layer in a continuous or non-continuous time interval (see Template 4.112)', +'113-253':'Reserved', '254':'CCITT IA5 character string (see Template 4.254)', '255-999':'Reserved', '1000':'Cross-section of analysis and forecast at a point in time. (see Template 4.1000)', @@ -224,7 +231,10 @@ '16':'Physical Retrieval', '17':'Regression Analysis', '18':'Difference Between Two Forecasts', -'19-191':'Reserved', +'19':'First guess', +'20':'Analysis increment', +'21':'Initialization increment for analysis', +'22-191':'Reserved', '192-254':'Reserved for Local Use', '192':'Forecast Confidence Indicator', '193':'Probability-matched Mean', @@ -276,7 +286,9 @@ '14':['Level of free convection (LFC)','unknown'], '15':['Convection condensation level (CCL)','unknown'], '16':['Level of neutral buoyancy or equilibrium (LNB)','unknown'], -'17-19':['Reserved','unknown'], +'17':['Departure level of the most unstable parcel of air (MUDL)','unknown'], +'18':['Departure level of a mixed layer parcel of air with specified layer depth','Pa'], +'19':['Reserved','unknown'], '20':['Isothermal Level','K'], '21':['Lowest level where mass density exceeds the specified value (base for a given threshold of mass density)','kg m-3'], '22':['Highest level where mass density exceeds the specified value (top for a given threshold of mass density)','kg m-3'], @@ -462,7 +474,13 @@ '7':'Covariance (temporal variance)', '8':'Difference ( value at the beginning of the time range minus value at the end)', '9':'Ratio', -'13-191':'Reserved', +'10':'Standardized Anomaly', +'11':'Summation', +'12':'Return period', +'13-99':'Reserved', +'100':'Severity', +'101':'Mode', +'102-191':'Reserved', '192-254':'Reserved for Local Use', '192':'Climatological Mean Value: multiple year averages of quantities which are themselves means over some period of time (P2) less than a year. The reference time (R) indicates the date and time of the start of a period of time, given by R to R + P2, over which a mean is formed; N indicates the number of such period-means that are averaged together to form the climatological value, assuming that the N period-mean fields are separated by one year. The reference time indicates the start of the N-year climatology. N is given in octets 22-23 of the PDS. If P1 = 0 then the data averaged in the basic interval P2 are assumed to be continuous, i.e., all available data are simply averaged together. If P1 = 1 (the units of time - octet 18, code table 4 - are not relevant here) then the data averaged together in the basic interval P2 are valid only at the time (hour, minute) given in the reference time, for all the days included in the P2 period. The units of P2 are given by the contents of octet 18 and Table 4.', '193':'Average of N forecasts (or initialized analyses); each product has forecast period of P1 (P1=0 for initialized analyses); products have reference times at intervals of P2, beginning at the given reference time.', @@ -968,6 +986,106 @@ '65535':['Missing','unknown'], } +table_4_234 = { +'1':'Crops, mixed farming', +'2':'Short grass', +'3':'Evergreen needleleaf trees', +'4':'Deciduous needleleaf trees', +'5':'Deciduous broadleaf trees', +'6':'Evergreen broadleaf trees', +'7':'Tall grass', +'8':'Desert', +'9':'Tundra', +'10':'Irrigated corps', +'11':'Semidesert', +'12':'Ice caps and glaciers', +'13':'Bogs and marshes', +'14':'Inland water', +'15':'Ocean', +'16':'Evergreen shrubs', +'17':'Deciduous shrubs', +'18':'Mixed forest', +'19':'Interrupted forest', +'20':'Water and land mixtures', +'21-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + +table_4_235 = { +'0':'Total Wave Spectrum (combined wind waves and swell)', +'1':'Generalized Partition', +'2-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + +table_4_236 = { +'1':'Coarse', +'2':'Medium', +'3':'Medium-fine', +'4':'Fine', +'5':'Very-fine', +'6':'Organic', +'7':'Tropical-organic', +'8-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + +table_4_238 = { +'0':'Reserved', +'1':'Aviation', +'2':'Lightning', +'3':'Biogenic Sources', +'4':'Anthropogenic sources', +'5':'Wild fires', +'6':'Natural sources', +'7':'Bio-fuel', +'8':'Volcanoes', +'9':'Fossil-fuel', +'10':'Wetlands', +'11':'Oceans', +'12':'Elevated anthropogenic sources', +'13':'Surface anthropogenic sources', +'14':'Agriculture livestock', +'15':'Agriculture soils', +'16':'Agriculture waste burning', +'17':'Agriculture (all)', +'18':'Residential, commercial and other combustion', +'19':'Power generation', +'20':'Super power stations', +'21':'Fugitives', +'22':'Industrial process', +'23':'Solvents', +'24':'Ships', +'25':'Wastes', +'26':'Road transportation', +'27':'Off-road transportation', +'28-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + +table_4_239 = { +'0':'Reserved', +'1':'Bog', +'2':'Drained', +'3':'Fen', +'4':'Floodplain', +'5':'Mangrove', +'6':'Marsh', +'7':'Rice', +'8':'Riverine', +'9':'Salt Marsh', +'10':'Swamp', +'11':'Upland', +'12':'Wet tundra', +'13-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + table_4_243 = { '0':'Reserved', '1':'Evergreen broadleaved forest', @@ -1014,6 +1132,15 @@ '255':'Missing', } +table_4_244 = { +'0':'No Quality Information Available', +'1':'Failed', +'2':'Passed', +'3-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + table_4_246 = { '0':'No thunderstorm occurrence', '1':'Weak thunderstorm', @@ -1067,6 +1194,15 @@ '255':'Missing', } +table_4_251 = { +'0':'Undefined Sequence', +'1':'Geometric sequence,(see Note 1)', +'2':'Arithmetic sequence,(see Note 2)', +'3-191':'Reserved', +'192-254':'Reserved for Local Use', +'255':'Missing', +} + table_scale_time_hours = { '0': 60., '1': 1., diff --git a/grib2io/tables/section4_discipline0.py b/grib2io/tables/section4_discipline0.py index 914be68..a0e8cc9 100644 --- a/grib2io/tables/section4_discipline0.py +++ b/grib2io/tables/section4_discipline0.py @@ -181,28 +181,6 @@ '126':['Presence of blizzard','See Table 4.222','PBLIZZ'], '127':['Ice pellets (non-water equivalent) precipitation rate','m s-1','ICEP'], '128':['Total solid precipitation rate','kg m-2 s-1','TSPRATE'], -'129':['Effective radius of cloud water','m','ERADCW'], -'130':['Effective radius of rain','m','ERADRAIN'], -'131':['Effective radius of cloud ice','m','ERADCICE'], -'132':['Effective radius of snow','m','ERADSNOW'], -'133':['Effective radius of graupel','m','ERADGRL'], -'134':['Effective radius of hail','m','ERADHAIL'], -'135':['Effective radius of subgrid liquid clouds','m','ERADSLC'], -'136':['Effective radius of subgrid ice clouds','m','ERADSIC'], -'137':['Effective aspect ratio of rain','unknown','ERATIOR'], -'138':['Effective aspect ratio of cloud ice','unknown','ERATIOCI'], -'139':['Effective aspect ratio of snow','unknown','ERATIOS'], -'140':['Effective aspect ratio of graupel','unknown','ERATIOG'], -'141':['Effective aspect ratio of hail','unknown','ERATIOH'], -'142':['Effective ratio of subgrid ice clouds','unknown','ERATOSIC'], -'143':['Potential evaporation rate','kg m-2 s-1','PERATE'], -'144':['Specific rain water content (convective)','kg kg-1','SRWATERC'], -'145':['Specific snow water content (convective)','kg kg-1','SSNOWWC'], -'146':['Cloud ice precipitation rate','kg m-2 s-1','CICEPR'], -'147':['Character of precipitation','See Table 4.249','PERATE'], -'148':['Snow evaporation rate','kg m-2 s-1','SNOWERAT'], -'149':['Cloud water mixing ratio','kg kg-1','CWATERMR'], -'150-128':['Reserved','unknown','unknown'], '129':['Effective Radius of Cloud Water','m','EFRCWAT'], '130':['Effective Radius of Rain','m','EFRRAIN'], '131':['Effective Radius of Cloud Ice','m','EFRCICE'], @@ -217,7 +195,15 @@ '140':['Effective Aspect Ratio of Graupel','unknown','EFARGRL'], '141':['Effective Aspect Ratio of Hail','unknown','EFARHAIL'], '142':['Effective Aspect Ratio of Subgrid Ice Clouds','unknown','EFARSIC'], -'143-191':['Reserved','unknown','unknown'], +'143':['Potential evaporation rate','kg m-2 s-1','PERATE'], +'144':['Specific rain water content (convective)','kg kg-1','SRWATERC'], +'145':['Specific snow water content (convective)','kg kg-1','SSNOWWC'], +'146':['Cloud ice precipitation rate','kg m-2 s-1','CICEPR'], +'147':['Character of precipitation','See Table 4.249','CHPRECIP'], +'148':['Snow evaporation rate','kg m-2 s-1','SNOWERAT'], +'149':['Cloud water mixing ratio','kg kg-1','CWATERMR'], +'150':['Column integrated eastward water vapour mass flux','kg m-1s-1','CEWVMF'], +'151-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['Categorical Rain','Code table 4.222','CRAIN'], '193':['Categorical Freezing Rain','Code table 4.222','CFRZR'], @@ -546,7 +532,9 @@ '47':['Volume Fraction of Cloud Water Droplets','Numeric','VFRCWD'], '48':['Volume Fraction of Cloud Ice Particles','Numeric','VFRCICE'], '49':['Volume Fraction of Cloud (Ice and/or Water)','Numeric','VFRCIW'], -'50-191':['Reserved','unknown','unknown'], +'50':['Fog','%','FOG'], +'51':['Sunshine Duration Fraction','Proportion','SUNFRAC'], +'52-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['Non-Convective Cloud Cover','%','CDLYR'], '193':['Cloud Work Function','J kg-1','CWORK'], diff --git a/grib2io/tables/section4_discipline10.py b/grib2io/tables/section4_discipline10.py index 61f91aa..e5fbf6d 100644 --- a/grib2io/tables/section4_discipline10.py +++ b/grib2io/tables/section4_discipline10.py @@ -68,12 +68,31 @@ '66':['Peak Wave Period of Second Swell Partition','s','PWPSSPAR'], '67':['Peak Wave Period of Third Swell Partition','s','PWPTSPAR'], '68':['Peak Wave Direction of First Swell Partition','degree true','PWDFSPAR'], -'69':['Peak Wave Direction of Second Swell Partition','degree true','PWDFSPAR'], -'70':['Peak Wave Direction of First Swell Partition','degree true','PWDSSPAR'], +'69':['Peak Wave Direction of Second Swell Partition','degree true','PWDSSPAR'], +'70':['Peak Wave Direction of Third Swell Partition','degree true','PWDTSPAR'], '71':['Peak Direction of Wind Waves','degree true','PDWWAVE'], '72':['Peak Direction of Total Swell','degree true','PDTSWELL'], '73':['Whitecap Fraction','fraction','WCAPFRAC'], -'74-191':['Reserved','unknown','unknown'], +'74':['Mean Direction of Total Swell','degree','MDTSWEL'], +'75':['Mean Direction of Wind Waves','degree','MDWWAVE'], +'76':['Charnock','Numeric','CHNCK'], +'77':['Wave Spectral Skewness','Numeric','WAVESPSK'], +'78':['Wave Energy Flux Magnitude','W m-1','WAVEFMAG'], +'79':['Wave Energy Flux Mean Direction','degree true','WAVEFDIR'], +'80':['Raio of Wave Angular and Frequency width','Numeric','RWAVEAFW'], +'81':['Free Convective Velocity over the Oceans','m s-1','FCVOCEAN'], +'82':['Air Density over the Oceans','kg m-3','AIRDENOC'], +'83':['Normalized Energy Flux into Waves','Numeric','NEFW'], +'84':['Normalized Stress into Ocean','Numeric','NSOCEAN'], +'85':['Normalized Energy Flux into Ocean','Numeric','NEFOCEAN'], +'86':['Surface Elevation Variance due to Waves (over all frequencies and directions)','m2 s rad-1','SEVWAVE'], +'87':['Wave Induced Mean Se Level Correction','m','WAVEMSLC'], +'88':['Spectral Width Index','Numeric','SPECWI'], +'89':['Number of Events in Freak Wave Statistics','Numeric','EFWS'], +'90':['U-Component of Surface Momentum Flux into Ocean','N m-2','USMFO'], +'91':['U-Component of Surface Momentum Flux into Ocean','N m-2','VSMFO'], +'92':['Wave Turbulent Energy Flux into Ocean','W m-2','WAVETEFO'], +'93-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['Wave Steepness','proportion','WSTP'], '193':['Wave Length','unknown','WLENG'], @@ -85,7 +104,9 @@ '2':['U-Component of Current','m s-1','UOGRD'], '3':['V-Component of Current','m s-1','VOGRD'], '4':['Rip Current Occurrence Probability','%','RIPCOP'], -'5-191':['Reserved','unknown','unknown'], +'5':['Eastward Current','m s-1','EASTCUR'], +'6':['Northward Current','m s-1','NRTHCUR'], +'7-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['Ocean Mixed Layer U Velocity','m s-1','OMLU'], '193':['Ocean Mixed Layer V Velocity','m s-1','OMLV'], @@ -108,8 +129,17 @@ '11':['Meridional Vector Component of Vertically Integrated Ice Internal Pressure','Pa m','MVCICEP'], '12':['Compressive Ice Strength','N m-1','CICES'], '13':['Snow Temperature (over sea ice)','K','SNOWTSI'], -'14':['Albedo','Numeric','ALBICE'], -'15-191':['Reserved','unknown','unknown'], +'14':['Albedo','Numeric','ALBDOICE'], +'15':['Sea Ice Volume per Unit Area','m3m-2','SICEVOL'], +'16':['Snow Volume Over Sea Ice per Unit Area','m3m-2','SNVOLSI'], +'17':['Sea Ice Heat Content','J m-2','SICEHC'], +'18':['Snow over Sea Ice Heat Content','J m-2','SICEHC'], +'19':['Ice Freeboard Thickness','m','ICEFTHCK'], +'20':['Ice Melt Pond Fraction','fraction','ICEMPF'], +'21':['Ice Melt Pond Depth','m','ICEMPD'], +'22':['Ice Melt Pond Volume per Unit Area','m3m-2','ICEMPF'], +'23':['Sea Ice Fraction Tendency due to Parameterization','s-1','SIFTP'], +'24-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '255':['Missing','unknown','unknown'], } @@ -200,7 +230,21 @@ '26':['Y-Component Water Velocity','m s-1','YCOMPWV'], '27':['Upward Water Velocity','m s-1','UPWWVEL'], '28':['Vertical Eddy Diffusivity','m2 s-1','VEDDYDIF'], -'29-191':['Reserved','unknown','unknown'], +'29':['Bottom Pressure Equivalent Height','m','BPEH'], +'30':['Fresh Water Flux into Sea Water from Rivers','kg m-2s-1','FWFSW'], +'31':['Fresh Water Flux Correction','kg m-2s-1','FWFC'], +'31':['Fresh Water Flux Correction','kg m-2s-1','FWFC'], +'32':['Virtual Salt Flux into Sea Water','g kg m-2s-1','VSFSW'], +'33':['Virtual Salt Flux Correction','g kg m-2s-1','VSFC'], +'34':['Sea Water Temperature Tendency due to Newtonian Relaxation','K s-1','SWTTNR'], +'35':['Sea Water Salinity Tendency due to Newtonian Relaxation','g kg m-2s-1','SWSTNR'], +'36':['Sea Water Temperature Tendency due to Parameterization','K s-1','SWTTP'], +'37':['Sea Water Salinity Tendency due to Parameterization','g kg m-2s-1','SWSTP'], +'38':['Eastward Sea Water Velocity Tendency Due To Parameterization','m-2s-1','ESWVP'], +'39':['Northward Sea Water Velocity Tendency Due To Parameterization','m-2s-1','NSWVP'], +'40':['Sea Water Temperature Tendency Due to Direct Bias Correction','K s-1','SWTTBC'], +'41':['Sea Water Salinity Tendency due to Direct Bias Correction','g kg m-2s-1','SWSTBC'], +'42-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['3-D Temperature','° c','WTMPC'], '193':['3-D Salinity','psu','SALIN'], diff --git a/grib2io/tables/section4_discipline2.py b/grib2io/tables/section4_discipline2.py index b88107a..103b618 100644 --- a/grib2io/tables/section4_discipline2.py +++ b/grib2io/tables/section4_discipline2.py @@ -44,6 +44,23 @@ '42':['Water Runoff and Drainage Rate','kg m-2 s-1','WRDRATE'], '43':['Drainage direction','See Table 4.250','DRAINDIR'], '44':['Upstream Area','m2','UPSAREA'], +'45':['Wetland Cover','Proportion','WETCOV'], +'46':['Wetland Type','See Table 4.239','WETTYPE'], +'47':['Irrigation Cover','Proportion','IRRCOV'], +'48':['C4 Crop Cover','Proportion','CROPCOV'], +'49':['C4 Grass Cover','Proportion','GRASSCOV'], +'50':['Skin Resovoir Content','kg m-2','SKINRC'], +'51':['unknown','unknown','unknown'], +'52':['unknown','unknown','unknown'], +'53':['unknown','unknown','unknown'], +'54':['unknown','unknown','unknown'], +'55':['unknown','unknown','unknown'], +'56':['unknown','unknown','unknown'], +'57':['unknown','unknown','unknown'], +'58':['unknown','unknown','unknown'], +'59':['unknown','unknown','unknown'], +'60':['unknown','unknown','unknown'], +'61':['unknown','unknown','unknown'], '45-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '192':['Volumetric Soil Moisture Content','Fraction','SOILW'], @@ -93,7 +110,7 @@ '236':['Water Storage in Aquifer','Kg m-2','WATERSA'], '237':['Evaporation of Intercepted Water','Kg m-2','EIWATER'], '238':['Plant Transpiration','Kg m-2','PLANTTR'], -'239':['Soil Surface Evaporation','Kg m-2','SOILSE'], +'239':['Soil Surface Evaporation','SOILSE','unknown'], '255':['Missing','unknown','unknown'], } table_4_2_2_1 = { diff --git a/grib2io/tables/section4_discipline20.py b/grib2io/tables/section4_discipline20.py new file mode 100644 index 0000000..5314bd7 --- /dev/null +++ b/grib2io/tables/section4_discipline20.py @@ -0,0 +1,35 @@ +table_4_2_20_0 = { +'0':['Universal Thermal Climate Index','K','UTHCIDX'], +'1':['Mean Radiant Temperature','K','MEANRTMP'], +'2':['Wet-bulb Globe Temperature (see Note)','K','WETBGTMP'], +'3':['Globe Temperature (see Note)','K','GLOBETMP'], +'4':['Humidex','K','HUMIDX'], +'5':['Effective Temperature','K','EFFTEMP'], +'6':['Normal Effective Temperature','K','NOREFTMP'], +'7':['Standard Effective Temperature','K','STDEFTMP'], +'8':['Physiological Equivalent Temperature','K','PEQUTMP'], +'9-191':['Reserved','unknown','unknown'], +'192-254':['Reserved for Local Use','unknown','unknown'], +'255':['Missing','unknown','unknown'], +} +table_4_2_20_1 = { +'0':['Malaria Cases','Fraction','MALACASE'], +'1':['Malaria Circumsporozoite Protein Rate','Fraction','MACPRATE'], +'2':['Plasmodium Falciparum Entomological Inoculation Rate','Bites per day per person','PFEIRATE'], +'3':['Human Bite Rate by Anopheles Vectors','Bites per day per person','HBRATEAV'], +'4':['Malaria Immunity','Fraction','MALAIMM'], +'5':['Falciparum Parasite Rates','Fraction','FALPRATE'], +'6':['Detectable Falciparum Parasite Ratio (after day 10)','Fraction','DFPRATIO'], +'7':['Anopheles Vector to Host Ratio','Fraction','AVHRATIO'], +'8':['Anopheles Vector Number','Number m-2','AVECTNUM'], +'9':['Fraction of Malarial Vector Reproductive Habitat','Fraction','FMALVRH'], +'10-191':['Reserved','unknown','unknown'], +'192-254':['Reserved for Local Use','unknown','unknown'], +'255':['Missing','unknown','unknown'], +} +table_4_2_20_2 = { +'0':['Population Density','Person m-2','POPDEN'], +'1-191':['Reserved','unknown','unknown'], +'192-254':['Reserved for Local Use','unknown','unknown'], +'255':['Missing','unknown','unknown'], +} diff --git a/grib2io/tables/section4_discipline3.py b/grib2io/tables/section4_discipline3.py index 3758a1f..4678c02 100644 --- a/grib2io/tables/section4_discipline3.py +++ b/grib2io/tables/section4_discipline3.py @@ -42,7 +42,8 @@ '27':['Bidirectional Reflecance Factor','Numeric','BRFLF'], '28':['Brightness Temperature','K','SPBRT'], '29':['Scaled Radiance','Numeric','SCRAD'], -'30-97':['Reserved','unknown','unknown'], +'30':['Reflectance in 0.4 Micron Channel','%','RFL04'], +'31-97':['Reserved','unknown','unknown'], '98':['Correlation coefficient between MPE rain rates for the co-located IR data and the microwave data rain rates','Numeric','CCMPEMRR'], '99':['Standard deviation between MPE rain rates for the co-located IR data and the microwave data rain rates','Numeric','SDMPEMRR'], '100-191':['Reserved','unknown','unknown'], diff --git a/grib2io/tables/section4_discipline4.py b/grib2io/tables/section4_discipline4.py index 6a0fe3b..f8ab312 100644 --- a/grib2io/tables/section4_discipline4.py +++ b/grib2io/tables/section4_discipline4.py @@ -101,7 +101,8 @@ '5':['White Light Coronagraph Radiance','W sr-1 m-2','WHTCOR'], '6':['Heliospheric Radiance','W sr-1 m-2','HELCOR'], '7':['Thematic Mask','Numeric','MASK'], -'8-191':['Reserved','unknown','unknown'], +'8':['Solar Induced Chlorophyll Fluorscence','W sr-1 m-2','SICFL'], +'9-191':['Reserved','unknown','unknown'], '192-254':['Reserved for Local Use','unknown','unknown'], '255':['Missing','unknown','unknown'], } diff --git a/grib2io/templates.py b/grib2io/templates.py index d1a54bd..f396ee6 100644 --- a/grib2io/templates.py +++ b/grib2io/templates.py @@ -276,9 +276,9 @@ def __set__(self, obj, value): class EarthParams: def __get__(self, obj, objtype=None): - if obj.gridDefinitionSection[4] in {50,51,52,1200}: + if obj.section3[5] in {50,51,52,1200}: return None - return tables.earth_params[str(obj.section3[5])] + return tables.get_table('earth_params')[str(obj.section3[5])] def __set__(self, obj, value): raise RuntimeError @@ -336,45 +336,48 @@ def __get__(self, obj, objtype=None): def __set__(self, obj, value): obj.section3[5] = value +class EarthShape: + def __get__(self, obj, objtype=None): + return obj._earthparams['shape'] + def __set__(self, obj, value): + raise RuntimeError + class EarthRadius: def __get__(self, obj, objtype=None): - earthparams = obj._earthparams - if earthparams['shape'] == 'spherical': - if earthparams['radius'] is None: + ep = obj._earthparams + if ep['shape'] == 'spherical': + if ep['radius'] is None: return obj.section3[7]/(10.**obj.section3[6]) else: - return earthparams['radius'] - if earthparams['shape'] == 'oblateSpheriod': - if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None: - return obj.section3[7]/(10.**obj.section3[6]) - else: - return earthparams['radius'] + return ep['radius'] + elif ep['shape'] in {'ellipsoid','oblateSpheriod'}: + return None def __set__(self, obj, value): raise RuntimeError class EarthMajorAxis: def __get__(self, obj, objtype=None): - earthparams = obj._earthparams - if earthparams['shape'] == 'spherical': + ep = obj._earthparams + if ep['shape'] == 'spherical': return None - if earthparams['shape'] == 'oblateSpheriod': - if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None: + elif ep['shape'] in {'ellipsoid','oblateSpheriod'}: + if ep['major_axis'] is None and ep['minor_axis'] is None: return obj.section3[9]/(10.**obj.section3[8]) else: - return earthparams['major_axis'] + return ep['major_axis'] def __set__(self, obj, value): raise RuntimeError class EarthMinorAxis: def __get__(self, obj, objtype=None): - earthparams = obj._earthparams - if earthparams['shape'] == 'spherical': + ep = obj._earthparams + if ep['shape'] == 'spherical': return None - if earthparams['shape'] == 'oblateSpheriod': - if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None: + if ep['shape'] in {'ellipsoid','oblateSpheriod'}: + if ep['major_axis'] is None and ep['minor_axis'] is None: return obj.section3[11]/(10.**section3[10]) else: - return earthparams['minor_axis'] + return ep['minor_axis'] def __set__(self, obj, value): raise RuntimeError diff --git a/make_grib2_tables/get-ncep-grib2-sect4-parameters-table.py b/make_grib2_tables/get-ncep-grib2-sect4-parameters-table.py index 94484a0..2ff4855 100755 --- a/make_grib2_tables/get-ncep-grib2-sect4-parameters-table.py +++ b/make_grib2_tables/get-ncep-grib2-sect4-parameters-table.py @@ -33,7 +33,7 @@ print(name," = {") for idx,row in df.iterrows(): parmnum = row['Number'] - parmname = row['Parameter'].replace('*','').replace('- Parameter deprecated','').strip() + parmname = str(row['Parameter']).replace('*','').replace('- Parameter deprecated','').strip() parmname = parmname.replace("\'",'') units = row['Units'] if row['Units'] != 'nan' else 'unknown' abbrev = row['Abbrev'] if row['Abbrev'] != 'nan' else 'unknown' diff --git a/make_grib2_tables/make-ncep-grib2-tables.sh b/make_grib2_tables/make-ncep-grib2-tables.sh index 3a7f13d..ababc7d 100755 --- a/make_grib2_tables/make-ncep-grib2-tables.sh +++ b/make_grib2_tables/make-ncep-grib2-tables.sh @@ -42,19 +42,19 @@ done # Store the Earth params table here. This is custom to grib2io. echo "\t - Earth params table" cat << EOF >> section3.py -earth_params = { +table_earth_params = { '0':{'shape':'spherical','radius':6367470.0}, '1':{'shape':'spherical','radius':None}, '2':{'shape':'oblateSpheriod','major_axis':6378160.0,'minor_axis':6356775.0,'flattening':1.0/297.0}, '3':{'shape':'oblateSpheriod','major_axis':None,'minor_axis':None,'flattening':None}, '4':{'shape':'oblateSpheriod','major_axis':6378137.0,'minor_axis':6356752.314,'flattening':1.0/298.257222101}, -'5':{'shape':'oblateSpheriod','major_axis':6378137.0,'minor_axis':6356752.3142,'flattening':1.0/298.257223563}, +'5':{'shape':'ellipsoid','major_axis':6378137.0,'minor_axis':6356752.3142,'flattening':1.0/298.257222101}, '6':{'shape':'spherical','radius':6371229.0}, '7':{'shape':'oblateSpheriod','major_axis':None,'minor_axis':None,'flattening':None}, '8':{'shape':'spherical','radius':6371200.0}, } for i in range(9,256): - earth_params[str(i)] = {'shape':'unknown','radius':None} + table_earth_params[str(i)] = {'shape':'unknown','radius':None} EOF # ---------------------------------------------------------------------------------------- @@ -67,9 +67,9 @@ echo " -- Making section4.py" if [ -f section4.py ]; then rm -f section4.py; fi echo "\t - Parameter category tables" ./get-ncep-grib2-sect4-category-table.py > section4.py -for table in 4.0 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.15 4.91 4.201 4.202 4.203 4.204 4.205 4.206 \ - 4.207 4.208 4.209 4.210 4.211 4.212 4.213 4.215 4.216 4.217 4.218 4.222 \ - 4.223 4.224 4.227 4.228 4.233 4.243 4.246 4.247 4.248 4.249 4.250 +for table in 4.0 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.15 4.91 4.201 4.202 4.203 4.204 4.205 4.206 \ + 4.207 4.208 4.209 4.210 4.211 4.212 4.213 4.215 4.216 4.217 4.218 4.222 4.223 4.224 4.227 4.228 4.233 4.234 \ + 4.235 4.236 4.238 4.239 4.243 4.244 4.246 4.247 4.248 4.249 4.250 4.251 do echo "\t - Table $table" ./get-ncep-grib2-table.py $table >> section4.py @@ -148,6 +148,14 @@ do ./get-ncep-grib2-sect4-parameters-table.py 10 $table >> section4_discipline10.py done +# Discipline 20 +echo " -- Making section4_discipline20.py" +if [ -f section4_discipline20.py ]; then rm -f section4_discipline20.py; fi +for table in 0 1 2 +do + ./get-ncep-grib2-sect4-parameters-table.py 20 $table >> section4_discipline20.py +done + # ---------------------------------------------------------------------------------------- # Remove "See Note" strings from section 4 discipline files. # ----------------------------------------------------------------------------------------