@@ -45,7 +45,6 @@ def round(value: float):
45
45
46
46
return round
47
47
48
-
49
48
# Enforce precision
50
49
# Note the sensor accuracies listed here:
51
50
# https://essd.copernicus.org/articles/13/3819/2021/#section8
@@ -65,82 +64,28 @@ class BUFRVariables:
65
64
* heightOfSensorAboveLocalGroundOrDeckOfMarinePlatformWSPD: Corresponds to "#7#heightOfSensorAboveLocalGroundOrDeckOfMarinePlatform" which is height if anemometer relative to ground or deck of marine platform.
66
65
67
66
"""
68
-
69
- # Station type: "mobile" or "land"
70
- # ===============================
71
- # Fixed land station schema: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/307080
72
- # Mobile station schema: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/307090
73
-
74
- station_type : str
75
-
76
- # WMO station identifier
77
- # Land stations: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/301090
78
- # Mobile stations: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/301092
79
- # ======================================================================================================
80
67
wmo_id : str
68
+ station_type : str
81
69
timestamp : datetime .datetime
82
-
83
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/005001
84
- # Scale: 5, unit: degrees
85
- # TODO: Test if eccodes does the rounding as well. The rounding is was 6 which is larger that the scale.
86
- latitude : float = attrs .field (converter = round_converter (5 ))
87
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/006001
88
- # Scale: 5, unit: degrees
89
- longitude : float = attrs .field (converter = round_converter (5 ))
90
-
91
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/007030
92
- # Scale: 1, unit: m
70
+ relativeHumidity : float = attrs .field (converter = round_converter (0 ))
71
+ airTemperature : float = attrs .field (converter = round_converter (1 ))
72
+ pressure : float = attrs .field (converter = round_converter (1 ))
73
+ windDirection : float = attrs .field (converter = round_converter (0 ))
74
+ windSpeed : float = attrs .field (converter = round_converter (1 ))
75
+ latitude : float = attrs .field (converter = round_converter (6 ))
76
+ longitude : float = attrs .field (converter = round_converter (6 ))
93
77
heightOfStationGroundAboveMeanSeaLevel : float = attrs .field (
94
- converter = round_converter (1 )
78
+ converter = round_converter (2 )
95
79
)
96
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/007031
97
- # Scale: 1, unit: m
80
+ #
98
81
heightOfBarometerAboveMeanSeaLevel : float = attrs .field (
99
- converter = round_converter (1 ),
82
+ converter = round_converter (2 ),
100
83
)
101
-
102
- # Pressure information
103
- # ====================
104
- # Definition table: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/302031
105
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/010004
106
- # Scale: -1, unit: Pa
107
- nonCoordinatePressure : float = attrs .field (converter = round_converter (- 1 ))
108
- # There are two other pressure variables in the template: 007004 - pressure and 010062 24-hour pressure change
109
-
110
- # Basic synoptic "instantaneous" data
111
- # ===================================
112
- # Definition table: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/302035
113
- # This section only include the temperature and humidity data (302032).
114
- # Precipitation and cloud data are currently ignored.
115
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/007032
116
- # Scale: 2, unit: m
117
- # This is the first appearance of this variable id.
118
84
heightOfSensorAboveLocalGroundOrDeckOfMarinePlatformTempRH : float = attrs .field (
119
- converter = round_converter (2 ),
85
+ converter = round_converter (4 ),
120
86
)
121
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/012101
122
- # Scale: 2, unit: K
123
- airTemperature : float = attrs .field (converter = round_converter (2 ))
124
- # There is also a Dewpoint temperature in this template: 012103 which is currently unused.
125
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/012103
126
- # Scale: 0, unit: %
127
- relativeHumidity : float = attrs .field (converter = round_converter (0 ))
128
-
129
- # Basic synoptic "period" data
130
- # ============================
131
- # Definition table: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/302043
132
- # Wind data: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/302042
133
- # Wind direction: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/011001
134
- # Scale: 0, unit: degrees
135
- windDirection : float = attrs .field (converter = round_converter (0 ))
136
- # Wind speed: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/011002
137
- # Scale: 1, unit: m/s
138
- windSpeed : float = attrs .field (converter = round_converter (1 ))
139
- # https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/007032
140
- # Scale: 2, unit: m
141
- # This is the 7th appearance of this variable id.
142
87
heightOfSensorAboveLocalGroundOrDeckOfMarinePlatformWSPD : float = attrs .field (
143
- converter = round_converter (2 )
88
+ converter = round_converter (4 )
144
89
)
145
90
146
91
def as_series (self ) -> pd .Series :
@@ -184,7 +129,6 @@ def __eq__(self, other: "BUFRVariables"):
184
129
185
130
BUFR_TEMPLATES = {
186
131
"mobile" : {
187
- # Template definition: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/307090
188
132
"unexpandedDescriptors" : (307090 ), # message template, "synopMobil"
189
133
"edition" : 4 , # latest edition
190
134
"masterTableNumber" : 0 ,
@@ -200,7 +144,6 @@ def __eq__(self, other: "BUFRVariables"):
200
144
"compressedData" : 0 ,
201
145
},
202
146
"land" : {
203
- # Template definition: https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_D/307080
204
147
"unexpandedDescriptors" : (307080 ), # message template, "synopLand"
205
148
"edition" : 4 , # latest edition
206
149
"masterTableNumber" : 0 ,
@@ -303,11 +246,6 @@ def set_station(ibufr, station_type: str, wmo_id: str):
303
246
elif station_type == "land" :
304
247
# StationNumber for land stations are integeres
305
248
wmo_id_int = int (wmo_id )
306
- if wmo_id_int >= 1024 :
307
- raise ValueError (
308
- f"Invalid WMO ID { wmo_id } . Land station number must be less than 1024."
309
- "See https://vocabulary-manager.eumetsat.int/vocabularies/BUFR/WMO/32/TABLE_B/001002"
310
- )
311
249
station_config = dict (stationNumber = wmo_id_int )
312
250
else :
313
251
raise Exception (f"Unsupported station station type { station_type } " )
@@ -342,7 +280,7 @@ def set_AWS_variables(
342
280
343
281
set_bufr_value (ibufr , "relativeHumidity" , variables .relativeHumidity )
344
282
set_bufr_value (ibufr , "airTemperature" , variables .airTemperature )
345
- set_bufr_value (ibufr , "nonCoordinatePressure " , variables .nonCoordinatePressure )
283
+ set_bufr_value (ibufr , "pressure " , variables .pressure )
346
284
set_bufr_value (ibufr , "windDirection" , variables .windDirection )
347
285
set_bufr_value (ibufr , "windSpeed" , variables .windSpeed )
348
286
@@ -434,7 +372,7 @@ def get_bufr_value(msgid: int, key: str) -> float:
434
372
raise ValueError (f"Unsupported BUFR value type { type (value )} for key { key } " )
435
373
436
374
437
- def read_bufr_message (fp : BinaryIO , backwards_compatible : bool = False ) -> Optional [BUFRVariables ]:
375
+ def read_bufr_message (fp : BinaryIO ) -> Optional [BUFRVariables ]:
438
376
"""
439
377
Read and parse BUFR message from binary IO stream.
440
378
@@ -445,8 +383,6 @@ def read_bufr_message(fp: BinaryIO, backwards_compatible: bool = False) -> Optio
445
383
----------
446
384
fp
447
385
Readable binary io stream
448
- backwards_compatible
449
- Use legacy pressure if nonCoordinatePressure is nan
450
386
451
387
Returns
452
388
-------
@@ -499,19 +435,11 @@ def read_bufr_message(fp: BinaryIO, backwards_compatible: bool = False) -> Optio
499
435
f"Unknown BUFR template unexpandedDescriptors: { unexpanded_descriptors } "
500
436
)
501
437
502
- nonCoordinatePressure = get_bufr_value (ibufr , "nonCoordinatePressure" )
503
- if math .isnan (nonCoordinatePressure ) and backwards_compatible :
504
- nonCoordinatePressure = get_bufr_value (ibufr , "pressure" )
505
- if not math .isnan (nonCoordinatePressure ):
506
- logger .warning (
507
- f"nonCoordinatePressure is nan, using legacy pressure instead"
508
- )
509
-
510
438
variables = BUFRVariables (
511
439
timestamp = timestamp ,
512
440
relativeHumidity = get_bufr_value (ibufr , "relativeHumidity" ),
513
441
airTemperature = get_bufr_value (ibufr , "airTemperature" ),
514
- nonCoordinatePressure = nonCoordinatePressure ,
442
+ pressure = get_bufr_value ( ibufr , "pressure" ) ,
515
443
windDirection = get_bufr_value (ibufr , "windDirection" ),
516
444
windSpeed = get_bufr_value (ibufr , "windSpeed" ),
517
445
latitude = get_bufr_value (ibufr , "latitude" ),
@@ -557,6 +485,5 @@ def read_bufr_file(path: PathLike) -> pd.DataFrame:
557
485
message_vars = read_bufr_message (fp )
558
486
if message_vars is None :
559
487
break
560
- lines .append (message_vars .as_series ())
561
- data_frame = pd .DataFrame (lines ).set_index ("wmo_id" )
562
- return data_frame
488
+ lines .append (message_vars )
489
+ return pd .DataFrame (lines ).rename_axis ("message_index" )
0 commit comments