grib2io.utils
Collection of utility functions to assist in the encoding and decoding of GRIB2 Messages.
1""" 2Collection of utility functions to assist in the encoding and decoding 3of GRIB2 Messages. 4""" 5 6import g2clib 7import datetime 8import numpy as np 9import struct 10 11from .. import tables 12 13def int2bin(i,nbits=8,output=str): 14 """ 15 Convert integer to binary string or list 16 17 Parameters 18 ---------- 19 20 **`i`**: Integer value to convert to binary representation. 21 22 **`nbits`**: Number of bits to return. Valid values are 8 [DEFAULT], 16, 23 32, and 64. 24 25 **`output`**: Return data as `str` [DEFAULT] or `list` (list of ints). 26 27 Returns 28 ------- 29 30 `str` or `list` (list of ints) of binary representation of the integer value. 31 """ 32 i = int(i) if not isinstance(i,int) else i 33 assert nbits in [8,16,32,64] 34 bitstr = "{0:b}".format(i).zfill(nbits) 35 if output is str: 36 return bitstr 37 elif output is list: 38 return [int(b) for b in bitstr] 39 40 41def ieee_float_to_int(f): 42 """ 43 Convert an IEEE 32-bit float to a 32-bit integer. 44 45 Parameters 46 ---------- 47 48 **`f`**: Float value. 49 50 Returns 51 ------- 52 53 Numpy Int32 representation of an IEEE 32-bit float. 54 """ 55 i = struct.unpack('>i',struct.pack('>f',np.float32(f)))[0] 56 return np.int32(i) 57 58 59 60def ieee_int_to_float(i): 61 """ 62 Convert a 32-bit integer to an IEEE 32-bit float. 63 64 Parameters 65 ---------- 66 67 **`i`**: Integer value. 68 69 Returns 70 ------- 71 72 Numpy float32 73 """ 74 f = struct.unpack('>f',struct.pack('>i',np.int32(i)))[0] 75 return np.float32(f) 76 77 78 79def getmd5str(a): 80 """ 81 Generate a MD5 hash string from input list 82 """ 83 import hashlib 84 assert isinstance(a,list) or isinstance(a,bytes) 85 return hashlib.md5(''.join([str(i) for i in a]).encode()).hexdigest() 86 87 88def getdate(year,month,day,hour,minute=None,second=None): 89 """ 90 Build an integer date from component input. 91 92 **`year`**: Year in 4-digit format. 93 94 **`month`**: Month in 2-digit format. 95 96 **`day`**: Day in 2-digit format. 97 98 **`hour`**: Hour in 2-digit format. 99 100 **`minute`**: Minute in 2-digit format. This argument is required if second is provided, otherwise 101 it is optional. 102 103 **`second`**: Second in 2-digit format [OPTIONAL]. 104 """ 105 year_exp = 6 106 month_exp = 4 107 day_exp = 2 108 hour_exp = 0 109 #if second is not None and minute is None: 110 # raise ValueError("Must provide minute argument if second argument is provided.") 111 #year_exp = 6 112 #month_exp = 4 113 #day_exp = 2 114 #hour_exp = 0 115 #minute_exp = -2 116 #second_exp = -4 117 #if minute is not None: 118 # assert minute >= 0 and minute <= 60 119 # year_exp += 2 120 # month_exp += 2 121 # day_exp += 2 122 # hour_exp += 2 123 # minute_exp += 2 124 # second_exp += 2 125 #if second is not None: 126 # assert second >= 0 and second <= 60 127 # year_exp += 2 128 # month_exp += 2 129 # day_exp += 2 130 # hour_exp += 2 131 # minute_exp += 2 132 # second_exp += 2 133 idate = (year*pow(10,year_exp))+(month*pow(10,month_exp))+\ 134 (day*pow(10,day_exp))+(hour*pow(10,hour_exp)) 135 #if minute is not None: 136 # idate += minute*pow(10,minute_exp) 137 #if second is not None: 138 # idate += second*pow(10,second_exp) 139 return idate 140 141 142def getleadtime(idsec,pdtn,pdt): 143 """ 144 Computes the lead time (in units of hours) from using information from 145 GRIB2 Identification Section (Section 1), Product Definition Template 146 Number, and Product Definition Template (Section 4). 147 148 Parameters 149 ---------- 150 151 **`idsec`**: seqeunce containing GRIB2 Identification Section (Section 1). 152 153 **`pdtn`**: GRIB2 Product Definition Template Number 154 155 **`idsec`**: seqeunce containing GRIB2 Product Definition Template (Section 4). 156 157 Returns 158 ------- 159 160 **`lt`**: Lead time in units of hours 161 """ 162 refdate = datetime.datetime(*idsec[5:11]) 163 if pdtn == 8: 164 enddate = datetime.datetime(*pdt[15:21]) 165 td = enddate - refdate 166 lt = (td).total_seconds()/3600.0 167 elif pdtn == 9: 168 enddate = datetime.datetime(*pdt[22:28]) 169 td = enddate - refdate 170 lt = (td).total_seconds()/3600.0 171 elif pdtn == 10: 172 enddate = datetime.datetime(*pdt[16:22]) 173 td = enddate - refdate 174 lt = (td).total_seconds()/3600.0 175 elif pdtn == 11: 176 enddate = datetime.datetime(*pdt[18:24]) 177 td = enddate - refdate 178 lt = (td).total_seconds()/3600.0 179 elif pdtn == 12: 180 enddate = datetime.datetime(*pdt[17:23]) 181 td = enddate - refdate 182 lt = (td).total_seconds()/3600.0 183 else: 184 lt = pdt[8]*(tables.get_value_from_table(pdt[7],'scale_time_hours')) 185 return int(lt) 186 187 188def getduration(pdtn,pdt): 189 """ 190 Computes the duration time (in units of hours) from using information from 191 Product Definition Template Number, and Product Definition Template (Section 4). 192 193 Parameters 194 ---------- 195 196 **`pdtn`**: GRIB2 Product Definition Template Number 197 198 **`pdt`**: sequence containing GRIB2 Product Definition Template (Section 4). 199 200 Returns 201 ------- 202 203 **`dur`**: Duration time in units of hours 204 """ 205 if pdtn == 8: 206 dur = pdt[26]*(tables.get_value_from_table(pdt[25],'scale_time_hours')) 207 elif pdtn == 9: 208 dur = pdt[33]*(tables.get_value_from_table(pdt[32],'scale_time_hours')) 209 elif pdtn == 10: 210 dur = pdt[27]*(tables.get_value_from_table(pdt[26],'scale_time_hours')) 211 elif pdtn == 11: 212 dur = pdt[29]*(tables.get_value_from_table(pdt[28],'scale_time_hours')) 213 elif pdtn == 12: 214 dur = pdt[28]*(tables.get_value_from_table(pdt[27],'scale_time_hours')) 215 else: 216 dur = 0 217 return int(dur) 218 219 220def decode_wx_strings(lus): 221 """ 222 Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings. The 223 decode procedure is defined here: 224 225 https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info 226 227 Parameters 228 ---------- 229 230 **`lus`**: GRIB2 Local Use Section containing NDFD weather strings. 231 232 Returns 233 ------- 234 235 **`list`**: List of NDFD weather strings. 236 """ 237 assert lus[0] == 1 238 # Unpack information related to the simple packing method 239 # the packed weather string data. 240 ngroups = struct.unpack('>H',lus[1:3])[0] 241 nvalues = struct.unpack('>i',lus[3:7])[0] 242 refvalue = struct.unpack('>i',lus[7:11])[0] 243 dsf = struct.unpack('>h',lus[11:13])[0] 244 nbits = lus[13] 245 datatype = lus[14] 246 if datatype == 0: # Floating point 247 refvalue = np.float32(ieee_int_to_float(refvalue)*10**-dsf) 248 elif datatype == 1: # Integer 249 refvalue = np.int32(ieee_int_to_float(refvalue)*10**-dsf) 250 # Upack each byte starting at byte 15 to end of the local use 251 # section, create a binary string and append to the full 252 # binary string. 253 b = '' 254 for i in range(15,len(lus)): 255 iword = struct.unpack('>B',lus[i:i+1])[0] 256 b += bin(iword).split('b')[1].zfill(8) 257 # Iterate over the binary string (b). For each nbits 258 # chunk, convert to an integer, including the refvalue, 259 # and then convert the int to an ASCII character, then 260 # concatenate to wxstring. 261 wxstring = '' 262 for i in range(0,len(b),nbits): 263 wxstring += chr(int(b[i:i+nbits],2)+refvalue) 264 # Return string as list, split by null character. 265 return list(filter(None,wxstring.split('\0'))) 266 267 268def get_wgrib2_prob_string(probtype,sfacl,svall,sfacu,svalu): 269 """ 270 Return a wgrib2-formatted string explaining probabilistic 271 threshold informaiton. Logic from wgrib2 source, [Prob.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Prob.c), 272 is replicated here. 273 274 Parameters 275 ---------- 276 277 **`probtype`**: `int` type of probability (Code Table 4.9). 278 279 **`sfacl`**: `int` scale factor of lower limit. 280 281 **`svall`**: `int` scaled value of lower limit. 282 283 **`sfacu`**: `int` scale factor of upper limit. 284 285 **`svalu`**: `int` scaled value of upper limit. 286 287 Returns 288 ------- 289 290 **`str`**: wgrib2-formatted string of probability threshold. 291 """ 292 probstr = '' 293 lower = svall/(10**sfacl) 294 upper = svalu/(10**sfacu) 295 if probtype == 0: 296 probstr = 'prob <%g' % (lower) 297 elif probtype == 1: 298 probstr = 'prob >%g' % (upper) 299 elif probtype == 2: 300 if lower == upper: 301 probstr = 'prob =%g' % (lower) 302 else: 303 probstr = 'prob >=%g <%g' % (lower,upper) 304 elif probtype == 3: 305 probstr = 'prob >%g' % (lower) 306 elif probtype == 4: 307 probstr = 'prob <%g' % (upper) 308 return probstr
14def int2bin(i,nbits=8,output=str): 15 """ 16 Convert integer to binary string or list 17 18 Parameters 19 ---------- 20 21 **`i`**: Integer value to convert to binary representation. 22 23 **`nbits`**: Number of bits to return. Valid values are 8 [DEFAULT], 16, 24 32, and 64. 25 26 **`output`**: Return data as `str` [DEFAULT] or `list` (list of ints). 27 28 Returns 29 ------- 30 31 `str` or `list` (list of ints) of binary representation of the integer value. 32 """ 33 i = int(i) if not isinstance(i,int) else i 34 assert nbits in [8,16,32,64] 35 bitstr = "{0:b}".format(i).zfill(nbits) 36 if output is str: 37 return bitstr 38 elif output is list: 39 return [int(b) for b in bitstr]
Convert integer to binary string or list
Parameters
i
: Integer value to convert to binary representation.
nbits
: Number of bits to return. Valid values are 8 [DEFAULT], 16,
32, and 64.
output
: Return data as str
[DEFAULT] or list
(list of ints).
Returns
str
or list
(list of ints) of binary representation of the integer value.
42def ieee_float_to_int(f): 43 """ 44 Convert an IEEE 32-bit float to a 32-bit integer. 45 46 Parameters 47 ---------- 48 49 **`f`**: Float value. 50 51 Returns 52 ------- 53 54 Numpy Int32 representation of an IEEE 32-bit float. 55 """ 56 i = struct.unpack('>i',struct.pack('>f',np.float32(f)))[0] 57 return np.int32(i)
Convert an IEEE 32-bit float to a 32-bit integer.
Parameters
f
: Float value.
Returns
Numpy Int32 representation of an IEEE 32-bit float.
61def ieee_int_to_float(i): 62 """ 63 Convert a 32-bit integer to an IEEE 32-bit float. 64 65 Parameters 66 ---------- 67 68 **`i`**: Integer value. 69 70 Returns 71 ------- 72 73 Numpy float32 74 """ 75 f = struct.unpack('>f',struct.pack('>i',np.int32(i)))[0] 76 return np.float32(f)
Convert a 32-bit integer to an IEEE 32-bit float.
Parameters
i
: Integer value.
Returns
Numpy float32
80def getmd5str(a): 81 """ 82 Generate a MD5 hash string from input list 83 """ 84 import hashlib 85 assert isinstance(a,list) or isinstance(a,bytes) 86 return hashlib.md5(''.join([str(i) for i in a]).encode()).hexdigest()
Generate a MD5 hash string from input list
89def getdate(year,month,day,hour,minute=None,second=None): 90 """ 91 Build an integer date from component input. 92 93 **`year`**: Year in 4-digit format. 94 95 **`month`**: Month in 2-digit format. 96 97 **`day`**: Day in 2-digit format. 98 99 **`hour`**: Hour in 2-digit format. 100 101 **`minute`**: Minute in 2-digit format. This argument is required if second is provided, otherwise 102 it is optional. 103 104 **`second`**: Second in 2-digit format [OPTIONAL]. 105 """ 106 year_exp = 6 107 month_exp = 4 108 day_exp = 2 109 hour_exp = 0 110 #if second is not None and minute is None: 111 # raise ValueError("Must provide minute argument if second argument is provided.") 112 #year_exp = 6 113 #month_exp = 4 114 #day_exp = 2 115 #hour_exp = 0 116 #minute_exp = -2 117 #second_exp = -4 118 #if minute is not None: 119 # assert minute >= 0 and minute <= 60 120 # year_exp += 2 121 # month_exp += 2 122 # day_exp += 2 123 # hour_exp += 2 124 # minute_exp += 2 125 # second_exp += 2 126 #if second is not None: 127 # assert second >= 0 and second <= 60 128 # year_exp += 2 129 # month_exp += 2 130 # day_exp += 2 131 # hour_exp += 2 132 # minute_exp += 2 133 # second_exp += 2 134 idate = (year*pow(10,year_exp))+(month*pow(10,month_exp))+\ 135 (day*pow(10,day_exp))+(hour*pow(10,hour_exp)) 136 #if minute is not None: 137 # idate += minute*pow(10,minute_exp) 138 #if second is not None: 139 # idate += second*pow(10,second_exp) 140 return idate
Build an integer date from component input.
year
: Year in 4-digit format.
month
: Month in 2-digit format.
day
: Day in 2-digit format.
hour
: Hour in 2-digit format.
minute
: Minute in 2-digit format. This argument is required if second is provided, otherwise
it is optional.
second
: Second in 2-digit format [OPTIONAL].
143def getleadtime(idsec,pdtn,pdt): 144 """ 145 Computes the lead time (in units of hours) from using information from 146 GRIB2 Identification Section (Section 1), Product Definition Template 147 Number, and Product Definition Template (Section 4). 148 149 Parameters 150 ---------- 151 152 **`idsec`**: seqeunce containing GRIB2 Identification Section (Section 1). 153 154 **`pdtn`**: GRIB2 Product Definition Template Number 155 156 **`idsec`**: seqeunce containing GRIB2 Product Definition Template (Section 4). 157 158 Returns 159 ------- 160 161 **`lt`**: Lead time in units of hours 162 """ 163 refdate = datetime.datetime(*idsec[5:11]) 164 if pdtn == 8: 165 enddate = datetime.datetime(*pdt[15:21]) 166 td = enddate - refdate 167 lt = (td).total_seconds()/3600.0 168 elif pdtn == 9: 169 enddate = datetime.datetime(*pdt[22:28]) 170 td = enddate - refdate 171 lt = (td).total_seconds()/3600.0 172 elif pdtn == 10: 173 enddate = datetime.datetime(*pdt[16:22]) 174 td = enddate - refdate 175 lt = (td).total_seconds()/3600.0 176 elif pdtn == 11: 177 enddate = datetime.datetime(*pdt[18:24]) 178 td = enddate - refdate 179 lt = (td).total_seconds()/3600.0 180 elif pdtn == 12: 181 enddate = datetime.datetime(*pdt[17:23]) 182 td = enddate - refdate 183 lt = (td).total_seconds()/3600.0 184 else: 185 lt = pdt[8]*(tables.get_value_from_table(pdt[7],'scale_time_hours')) 186 return int(lt)
Computes the lead time (in units of hours) from using information from GRIB2 Identification Section (Section 1), Product Definition Template Number, and Product Definition Template (Section 4).
Parameters
idsec
: seqeunce containing GRIB2 Identification Section (Section 1).
pdtn
: GRIB2 Product Definition Template Number
idsec
: seqeunce containing GRIB2 Product Definition Template (Section 4).
Returns
lt
: Lead time in units of hours
189def getduration(pdtn,pdt): 190 """ 191 Computes the duration time (in units of hours) from using information from 192 Product Definition Template Number, and Product Definition Template (Section 4). 193 194 Parameters 195 ---------- 196 197 **`pdtn`**: GRIB2 Product Definition Template Number 198 199 **`pdt`**: sequence containing GRIB2 Product Definition Template (Section 4). 200 201 Returns 202 ------- 203 204 **`dur`**: Duration time in units of hours 205 """ 206 if pdtn == 8: 207 dur = pdt[26]*(tables.get_value_from_table(pdt[25],'scale_time_hours')) 208 elif pdtn == 9: 209 dur = pdt[33]*(tables.get_value_from_table(pdt[32],'scale_time_hours')) 210 elif pdtn == 10: 211 dur = pdt[27]*(tables.get_value_from_table(pdt[26],'scale_time_hours')) 212 elif pdtn == 11: 213 dur = pdt[29]*(tables.get_value_from_table(pdt[28],'scale_time_hours')) 214 elif pdtn == 12: 215 dur = pdt[28]*(tables.get_value_from_table(pdt[27],'scale_time_hours')) 216 else: 217 dur = 0 218 return int(dur)
Computes the duration time (in units of hours) from using information from Product Definition Template Number, and Product Definition Template (Section 4).
Parameters
pdtn
: GRIB2 Product Definition Template Number
pdt
: sequence containing GRIB2 Product Definition Template (Section 4).
Returns
dur
: Duration time in units of hours
221def decode_wx_strings(lus): 222 """ 223 Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings. The 224 decode procedure is defined here: 225 226 https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info 227 228 Parameters 229 ---------- 230 231 **`lus`**: GRIB2 Local Use Section containing NDFD weather strings. 232 233 Returns 234 ------- 235 236 **`list`**: List of NDFD weather strings. 237 """ 238 assert lus[0] == 1 239 # Unpack information related to the simple packing method 240 # the packed weather string data. 241 ngroups = struct.unpack('>H',lus[1:3])[0] 242 nvalues = struct.unpack('>i',lus[3:7])[0] 243 refvalue = struct.unpack('>i',lus[7:11])[0] 244 dsf = struct.unpack('>h',lus[11:13])[0] 245 nbits = lus[13] 246 datatype = lus[14] 247 if datatype == 0: # Floating point 248 refvalue = np.float32(ieee_int_to_float(refvalue)*10**-dsf) 249 elif datatype == 1: # Integer 250 refvalue = np.int32(ieee_int_to_float(refvalue)*10**-dsf) 251 # Upack each byte starting at byte 15 to end of the local use 252 # section, create a binary string and append to the full 253 # binary string. 254 b = '' 255 for i in range(15,len(lus)): 256 iword = struct.unpack('>B',lus[i:i+1])[0] 257 b += bin(iword).split('b')[1].zfill(8) 258 # Iterate over the binary string (b). For each nbits 259 # chunk, convert to an integer, including the refvalue, 260 # and then convert the int to an ASCII character, then 261 # concatenate to wxstring. 262 wxstring = '' 263 for i in range(0,len(b),nbits): 264 wxstring += chr(int(b[i:i+nbits],2)+refvalue) 265 # Return string as list, split by null character. 266 return list(filter(None,wxstring.split('\0')))
Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings. The decode procedure is defined here:
https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info
Parameters
lus
: GRIB2 Local Use Section containing NDFD weather strings.
Returns
list
: List of NDFD weather strings.
269def get_wgrib2_prob_string(probtype,sfacl,svall,sfacu,svalu): 270 """ 271 Return a wgrib2-formatted string explaining probabilistic 272 threshold informaiton. Logic from wgrib2 source, [Prob.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Prob.c), 273 is replicated here. 274 275 Parameters 276 ---------- 277 278 **`probtype`**: `int` type of probability (Code Table 4.9). 279 280 **`sfacl`**: `int` scale factor of lower limit. 281 282 **`svall`**: `int` scaled value of lower limit. 283 284 **`sfacu`**: `int` scale factor of upper limit. 285 286 **`svalu`**: `int` scaled value of upper limit. 287 288 Returns 289 ------- 290 291 **`str`**: wgrib2-formatted string of probability threshold. 292 """ 293 probstr = '' 294 lower = svall/(10**sfacl) 295 upper = svalu/(10**sfacu) 296 if probtype == 0: 297 probstr = 'prob <%g' % (lower) 298 elif probtype == 1: 299 probstr = 'prob >%g' % (upper) 300 elif probtype == 2: 301 if lower == upper: 302 probstr = 'prob =%g' % (lower) 303 else: 304 probstr = 'prob >=%g <%g' % (lower,upper) 305 elif probtype == 3: 306 probstr = 'prob >%g' % (lower) 307 elif probtype == 4: 308 probstr = 'prob <%g' % (upper) 309 return probstr
Return a wgrib2-formatted string explaining probabilistic threshold informaiton. Logic from wgrib2 source, Prob.c, is replicated here.
Parameters
probtype
: int
type of probability (Code Table 4.9).
sfacl
: int
scale factor of lower limit.
svall
: int
scaled value of lower limit.
sfacu
: int
scale factor of upper limit.
svalu
: int
scaled value of upper limit.
Returns
str
: wgrib2-formatted string of probability threshold.