Based on various questions from NWP users, this webpage answers FAQ regarding the Aeolus L2B BUFR format and its use for NWP.
The BUFR template document is here: AE-TN-ECMWF-L2BP_0073-L2B_BUFR_template_20151123_v1.00.pdf. The L2B EE format IODD also provides information (indirectly) on what the L2B BUFR contains: AE_IF_ECMWF_L2BP_001_IODD_20180215_v3.10.pdf i.e. a subset of the L2B EE format data is copied over to the L2B BUFR. There is also a new EE 2 BUFR conversion tool technical note: AE-TN-KNMI-BUFR-001_BufrConverter_SUM-20180413_v1.0.pdf
These changes (which came with v3.00 of the L2B processing) are some modifications to the original published template. We found that the WMO approved template cannot store the satellite range for Aeolus because the decision was taken to go for a lower orbit of 320 km (rather than 408 km); this change happened after we designed the template. The new satellite range (distance) values are outside the allowed ranges of the BUFR template! The 20xxxx descriptors modify the number of bits and the scaling so the numbers fit again. The only thing you need to do is allow the changed number of unexpanded descriptors in your code (63 in stead of 51). Actually, after expansion, the number of descriptors will be identical to the original template, i.e. it will be reduced to 51. You should not need any changed BUFR tables at all, since this is part of the official BUFR file format itself.
You should also know that we plan 2 more updates with the same method in our upcoming software version (L2Bp v3.10, to be released around late February 2019). With that update we will also modify the derivative values (dhlos_dT and dhlos_dp) for the Rayleigh channel (so adding another 8 20xxxx descriptors) to have increased precision (by mistake we didn't have enough). For this planned change you will need to change the number unexpanded descriptors in your code to 71. You should not need any changed BUFR tables to decode these changed files.
Note there is a mistake in L2Bp v3.01 EE and hence BUFR which means the value the dhlos_dp value is written out in units of m/s/hPa, rather than being converted to the correct units defined in the IODD (m/s/Pa). This bug is fixed in the upcoming L2Bp v3.10.
Miscellaneous advice: If you mix the Aeolus BUFR messages with other observations in the same BUFR file, then recognizing the data type is not as straightforward now, but it is not too difficult. For example looking at the 13th descriptor "005069 ADM RECEIVER CHANNEL" this one is unique to this Aeolus template and will never be used by any other observation, nor will it shift due to the mentioned changes.
The L2B Rayleigh winds (molecular scattering) are corrected for a sensitivity to temperature (Doppler broadening) and pressure (Brillouin scattering) via the use of a priori NWP information. Note that the Mie winds are not affected by temperature and pressure i.e. don't need a correction. The Rayleigh winds would be biased if we didn't account for this (by e.g. 5 m/s). The L2B processing documentation e.g. ATBD, which describes the Rayleigh-Brillouin correction.
Aeolus L2B BUFR doesn't provide a vector wind or a u-wind observation, but a horizontal line-of-sight (HLOS) wind component (which can easily be converted to LOS wind if you wish (using the elevation angle)). HLOS wind is just a projection of the LOS wind onto the horizontal plane.
If your NWP model has the vertical wind component available, you may wish to forward model HLOS wind also including the vertical wind "contamination" (which is what Aeolus actually measures), in which case you should include the vertical wind component and elevation angle in the forward model i.e. HLOS_wind = -u.sin(azimuth) - v.cos(azimuth) -w.cot(elevation). We assume generally that because the w component averaged over 80 km is small in the conditions Aeolus will sample, then we can ignore the vertical wind.
You can expect a fair number good Mie winds (particularly Mie-cloudy), but also a fair number of invalid ones. Note there are 4 types of winds available: Mie-cloudy, Mie-clear, Rayleigh-cloudy, Rayleigh-clear.
Generally the Mie-cloudy and Rayleigh-clear to be the best quality winds, as you can imagine given the origin of the backscatter signal. It is possible to some reasonable Mie-clear winds by misclassification of the measurement-level data - we classify measurements-bins into clear or cloudy based on their estimated scattering ratio (a L1B variable). Rayleigh-cloudy are generally biased winds due to an imperfect correction for the Mie backscatter in the Rayleigh channel signals.
In the latest code (from L2Bp v3.00, rather than v2.30 that produced the BUFR you look at) we by default set all Mie-clear and all Rayleigh-cloudy winds to invalid to guide users to avoid them for DA (initially at least).
We added profile information for those that are restricted to assimilate the data like it is old-style radiosonde profile i.e. one geolocation per profile. Also, it might be useful if users prefer to assimilate wind shear (if we had varying bias along the orbit we thought wind shear assimilation might be a solution).
Each L2B Earth Explorer file starts afresh in terms of the profile number and the associated wind ID numbers. We process each L1B EE file to one L2B EE file which then gets converted to one L2B BUFR file. Each L2B BUFR file will be sent to (or retrieved by) EUMETSAT for distribution on the GTS - I'm not sure yet how they will split the data.
Typically there is one L1B EE file per orbit (Svalbard to Svalbard ground station), but occasionally there are many orbits per L1B EE file, due to blind orbits when they can't dump the telemetry for a number of passes.
e.g. looking at an ASCII dump of one real L2B EE file, there are 908 profiles, the last profile has:
L2BC%Rayleigh_Wind_Profile_MDS(908)%start_of_obs_datetime = 07-OCT-2018 22:42:50.227159
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lat_start = -0999000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lat_average = -0081067802
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lat_stop = +0999000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lon_start = -0999000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lon_average = +0009943565
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_lon_stop = +0007517272
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_DateTime_Start = 07-OCT-2018 22:42:50.227159
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_DateTime_Average = 07-OCT-2018 22:43:01.467466
L2BC%Rayleigh_Wind_Profile_MDS(908)%Profile_DateTime_Stop = 07-OCT-2018 22:43:01.711158
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%Channel = Rayleigh_Channel
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%Obs_Type = Obs_Type_clear_returns
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%num_winds_in_profile = +013
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%profile_id_number = +0000000908
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(01) = +0000019407
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(02) = +0000019408
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(03) = +0000019409
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(04) = +0000019410
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(05) = +0000019411
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(06) = +0000019412
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(07) = +0000019413
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(08) = +0000019414
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(09) = +0000019415
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(10) = +0000019416
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(11) = +0000019417
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(12) = +0000019418
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(13) = +0000019419
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(14) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(15) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(16) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(17) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(18) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(19) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(20) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(21) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(22) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(23) = +0000000000
L2BC%Rayleigh_Wind_Profile_MDS(908)%L2B_Wind_Profile%wind_result_id_number(24) = +0000000000
The wind_id_number will start again from 1 in the next L2B EE file, as does the effective profile count.
When it comes to the L2B BUFR we store the profile number of each wind result as you will have noticed based on your email.
e.g. for one BUFR message (a dump of the BUFR to ASCII, using ECMWF's eccodes bufr_dump tool):
{
"key" : "profileNumber",
"value" :
[
32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
32, 32, 32, 33, 33, 33, 33, 33, 33, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
34
],
"units" : "Numeric"
},
[
{
"key" : "observationIdentifier",
"value" :
[
453, 454, 455, 456, 457, 458, 459, 460, 461, 462,
463, 464, 465, 466, 467, 468, 469, 470, 471, 472,
473, 474, 475, 476, 477, 478, 479, 480, 481, 482,
483, 484, 485, 486, 487, 488, 489, 490, 491, 492,
493, 494, 495, 496, 497, 498, 499, 500, 501, 502,
503
],
"units" : "Numeric"
},
So the profileNumber is equivalent to the index of the profile in the L2B EE file and the observationIdentifier is equivalent to the wind_result_id_number.