-
Notifications
You must be signed in to change notification settings - Fork 0
Description
TEMPO ozone data are a new product for the monitoring of ozone and air pollution from a geostationary satellite over North America. The L2 products (granules of data from a satellite overpass) have an instrument coordinate system using a non-standard encoding in the netCDF file. As a result, packages like stars and terra cannot successfully extract the data from these files. This issue has been flagged here.
Below is a demonstration of opening TEMPO L2 files with package ncdfCF. Please note that you need package version >=0.8.0.
library(ncdfCF)
ds <- open_ncdf("~/Downloads/tempo_o3prof_l2_v04_20250921t210803z_s012g02/TEMPO_O3PROF_L2_V04_20250921T210803Z_S012G02.nc")
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_precision'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_precision'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_error'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_error'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_apriori_profile'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_apriori_profile'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_apriori_profile_error'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_apriori_profile_error'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_altitude'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_altitude'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_altitude_bounds'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_altitude_bounds'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_temperature'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_temperature'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_pressure'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_pressure'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_profile_pressure_bounds'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_profile_pressure_bounds'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_pressure' found in
#> variable 'ozone_averaging_kernel'.
#> Warning: Unmatched `coordinates` value 'ozone_profile_altitude' found in
#> variable 'ozone_averaging_kernel'.
Oops. Bad encoding of the "coordinates" attribute in 11 variables. This will not affect the processing but not looking good.
(vars <- ds$var_names)
#> [1] "/product/ozone_profile"
#> [2] "/product/ozone_profile_precision"
#> [3] "/product/ozone_profile_error"
...
#> [51] "/qa_statistics/num_iterations"
#> [52] "/qa_statistics/fit_RMS"
#> [53] "/qa_statistics/avg_residuals"
The original post was about the "ozone_profile" so that is the first variable, located in the "product" group.
(o3 <- ds[[ vars[1L] ]])
#> <Variable> ozone_profile
#> Path name: /product/ozone_profile
#>
#> Values: (not loaded)
#>
#> Axes:
#> name long_name length values
#> layer 24 [1 ... 24]
#> xtrack pixel index along slit 512 [0 ... 511]
#> mirror_step scan mirror position index 132 [132 ... 263]
#>
#> Auxiliary longitude-latitude grid:
#> axis name extent unit
#> X longitude [-71.712 ... -45.730] degrees_east
#> Y latitude [17.378 ... 60.636] degrees_north
#>
#> Attributes:
#> name type length value
#> comment NC_CHAR 23 retrieved ozone profile
#> units NC_CHAR 2 DU
#> valid_min NC_FLOAT 1 -100
#> valid_max NC_FLOAT 1 100
#> _FillValue NC_FLOAT 1 -1.26765060022823e+30
#> coordinates NC_CHAR 69 time longitude latitude ozo...
Great, here's the data, but note how the axes are called "xtrack" and "mirror_step" and being just index values into the data array, not real coordinates. The data variable does have an "Auxiliary longitude-latitude grid", however, giving latitude-longitude values for each pixel in the data array. We can use the subset() method with those auxiliary coordinates as axis selectors to warp the instrument coordinate system to lat-lon:
# Using a resolution of 0.04 degrees here, the default for TEMPO L3 products.
(o3_ll <- o3$subset(longitude = NA, latitude = NA, layer = 24, .resolution = 0.04))
#> <Variable> ozone_profile
#>
#> Values: [-0.156455 ... 13.96814] DU
#> NA: 542558 (77.3%)
#>
#> Axes:
#> axis name long_name length values unit
#> X longitude pixel index along slit 649 [-71.691716 ... -45.771716] degrees_east
#> Y latitude scan mirror position index 1081 [17.398387 ... 60.598387] degrees_north
#> layer 1 [24]
#>
#> Attributes:
#> name type length value
#> comment NC_CHAR 23 retrieved ozone profile
#> units NC_CHAR 2 DU
#> valid_min NC_FLOAT 1 -100
#> valid_max NC_FLOAT 1 100
#> _FillValue NC_FLOAT 1 -1.26765060022823e+30
#> coordinates NC_CHAR 50 time ozone_profile_pressure...
#> actual_range NC_FLOAT 2 -0.156455, 13.968141
Objects from package ncdfCF can be read by stars:
library(stars)
#> Loading required package: abind
#> Loading required package: sf
#> Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE
(o3_stars <- st_as_stars(o3_ll))
#> stars object with 2 dimensions and 1 attribute
#> attribute(s):
#> Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
#> ozone_profile [DU] -0.1564551 6.509749 7.033861 7.18038 8.031126 13.96814 542558
#>
#> dimension(s):
#> from to offset delta refsys x/y
#> longitude 1 649 -71.71 0.04 OGC:CRS84 [x]
#> latitude 1 1081 17.38 0.04 OGC:CRS84 [y]
plot(o3_stars)
