Proposal status: FINAL DRAFT/2018-06-19.
- 1. Introduction
- 2. Swath Data Encodings
- Appendix A: Non-Compliant Geospatial Examples
- Appendix B: How To Contribute
- Appendix C: Decision Flowchart
- Appendix D: Revision History
- Appendix E: References
This is a proposal for an extension of the Climate and Forecast metadata convention (CF) to standardize the encodings of Earth Science swath data in the original instrument viewing geometry. The aim is to have some form of this document added to a future version of the CF convention. The proposal is based on the CF version 1.7 although backward compatibility is not necessarily an objective.
The work is done under the U.S. National Science Foundation award 1541031: "EarthCube IA: Advancing netCDF-CF for the Geoscience Community".
The community-provided examples were valuable resource in preparing this proposal. These examples are collected in a GitHub repository at https://github.com/diwg/diwg.
Encoding examples here are expressed using the NetCDF Common Data Language (CDL) with only the relevant file content to illustrate the concept. They should not be construed as complete and used as templates.
Earth Science swath data originates as electromagnetic radiation collected from a specific direction into a solid angle and then measured at a number of intervals of the electromagnetic spectrum, called bands or channels. The combination of the direction, the solid angle, and the instrument data acquisition settings defines one observation or measurement. At any given instant an instrument sweeps over an area of the Earth while its platform (an object carrying such instrument) moves. Successive observations are usually combined to cover a larger portion of the Earth, sometimes even the entire Earth. When these successive observations are plotted on maps they appear to cover a swath on the Earth’s surface, hence the name for this type of data.
Radiometric swath data are further processed to retrieve geophysical parameters. In the satellite remote sensing context, the former are commonly referred to as Level 1 while the latter are called Level 2 swath data. Thus there are two distinctive swath data domains for which we define encodings: radiometric and geophysical. The chief differences between these two domains are:
-
Spectral (band, channel) coordinates must be defined for all radiometric swath data.
-
The geospatial extent for radiometric swath data is always two-dimensional (area), while for geophysical swath data it can also be three-dimensional.
-
Geophysical swath data may also include coordinates that represent altitude.
The proposed encodings are independent from the observation method and are applicable to swath data acquired by instruments on either satellites, airplanes, or unmanned aerial systems. The swath_data
variable in the examples is a generic representation of any parameter that can be stored in swath data files. The order of its dimensions as shown in the examples is not the only one possible or allowed. It should be tailored to expected data access patterns in actual files.
Geospatial coordinates for swath data are comprised of a horizontal and, in some cases, a vertical component. The horizontal component reflects the instrument scanning and stepping in terms of the latitude and longitude for each observation. Because of this the rank of the latitude and longitude coordinates is at least two, but can be larger, with the slowest varying dimension representing forward (along-track) movement of the platform. The reference of latitude-longitude coordinates is a geodetic datum (planetodetic for other planetary bodies). The following example demonstrates a typical case of swath data latitude and longitude coordinates on the WGS-84 geoid.
dimensions: atrack = 78 ; (1) xtrack = 2048 ; (2) variables: float lat(atrack, xtrack) ; lat:units = "degrees_north" ; (3) lat:standard_name = "latitude" ; (4) float lon(atrack, xtrack) ; lon:units = "degrees_east" ; (3) lon:standard_name = "longitude" ; (4) int crs ; (5) crs:grid_mapping_name = "latitude_longitude"; (6) crs:longitude_of_prime_meridian = 0.0 ; (7) crs:semi_major_axis = 6378137.0 ; (7) crs:inverse_flattening = 298.257223563 ; (7)
-
The dimension representing along-track platform movement.
-
The dimension representing data collected across-track to platform movement.
-
Required use of the
units
attribute and its values for the latitude and longitude coordinates. -
Required use of the
standard_name
attribute, identifying the latitude and longitude coordinates. -
The grid mapping variable. The term "grid" is for historical reasons only. It’s name and data type are arbitrary.
-
The value is an identifier that can describe any combination of a geoid, coordinate reference system, and map projection. In this case it is the latitude-longitude reference system.
-
The attributes related to describing the WGS-84 geoid datum.
As an alternative to having latitude and longitude coordinates, projection coordinates (e.g., fixed grid over a map projection) may be employed instead. When used, there has to be a grid mapping variable describing the map projection. The example below shows the projection coordinates for swath data collected by a geostationary instrument.
dimensions: y = 1500 ; x = 2500 ; variables: short y(y) ; y:units = "radian" ; y:axis = "Y" ; y:standard_name = "projection_y_coordinate" ; (1) short x(x) ; x:units = "radian" ; x:axis = "X" ; x:standard_name = "projection_x_coordinate" ; (1) int goes_imager_projection ; (2) goes_imager_projection:grid_mapping_name = "geostationary" ; goes_imager_projection:perspective_point_height = 35786023. ; goes_imager_projection:semi_major_axis = 6378137. ; goes_imager_projection:semi_minor_axis = 6356752.31414 ; goes_imager_projection:inverse_flattening = 298.2572221 ; goes_imager_projection:latitude_of_projection_origin = 0. ; goes_imager_projection:longitude_of_projection_origin = -89.5 ; goes_imager_projection:sweep_angle_axis = "x" ;
-
Required use of the
standard_name
attribute with values that identify the projection coordinates. -
The grid mapping variable with the attributes describing the Geostationary projection.
Note
|
It is important to mention here that the requirements to provide geospatial coordinate data for every observation, or include latitude and longitude coordinates in addition to projection coordinates, does preclude the possibility of CF compliance for many existing archives of satellite swath data. For example:
|
The vertical component of geospatial coordinates represents the altitude associated with swath data. Any of the supported vertical coordinate types are acceptable.
Specifying time coordinates for swath data follows the pertinent CF convention rules. The rank of time coordinates can range from one (one-dimensional) up to the rank of the swath data variable to which they apply (2, 3, …, n-dimensional). The slowest varying coordinate dimension must represent forward (along-track) movement of the platform.
One dimensional time coordinate:
dimensions: time = 10 ; (1) variables: double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ;
-
The dimension represents forward (along track) platform movement. It can also be an unlimited dimension (
time = UNLIMITED
).
Two dimensional time coordinate:
dimensions: atrack = 78 ; xtrack = 2048 ; variables: double time(atrack, xtrack) ; (1) time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ;
-
Time coordinates with the rank greater than one must be listed in the
coordinates
attribute of their swath data variables.
Note
|
Some satellite swath data use the International Atomic Time (TAI) which currently is not supported by the CF convention (see this thread on the CF mailing list for background). The encoding examples in this proposal use the Gregorian calendar. |
The information about the electromagnetic radiation intervals (bands, channels) at which swath data were acquired is encoded as spectral coordinates. The coordinate values can either be stored as physical properties (wavelength, wavenumber, frequency) or alphanumeric strings.
For monotonically increasing or decreasing band data:
dimensions: band = 5 ; (1) variables: float band(band) ; (2) band:standard_name = "sensor_band_central_radiation_wavelength" ; (3) band:units = "μm" ;
-
Number of bands.
-
The
band
variable is a coordinate variable. -
One of the standard names specifically for numerical band data. The other two are
sensor_band_central_radiation_wavenumber
andsensor_band_central_radiation_frequency
. More generic namesradiation_frequency
andradiation_wavelength
can also be used when appropriate.
For non-monotonic band data:
dimensions: num_band = 5 ; (1) variables: double band(num_band) ; (2) band:standard_name = "sensor_band_central_radiation_wavenumber" ; band:units = "cm-1" ;
-
Number of bands.
-
The
band
variable must be listed in thecoordinates
attribute of its swath data variable.
Alphanumeric spectral coordinates are applicable to cases where bands cannot be differentiated solely numerically, for example, when polarization together with electromagnetic spectrum interval information has to be combined.
For the netCDF extended model (strongly recommended to use):
dimensions: num_band = 5 ; variables: string band(num_band) ; band:standard_name = "sensor_band_identifier" ;
For the netCDF classic model:
dimensions: num_band = 5 ; band_strlen = 10 ; (1) variables: char band(num_band, band_strlen) ; band:standard_name = "sensor_band_identifier" ; (2)
-
Number of characters of the longest band string identifier.
-
The standard name specifically for band string identifiers.
Multiband swath data are very common, collected over an area on the Earth as successive across-track observations at a number of different spectral bands.
dimensions: time = 120 ; scan = 512 ; band = 8 ; variables: float band(band) ; band:standard_name = "sensor_band_central_radiation_wavelength" ; band:units = "μm" ; float lat(time, scan) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, scan) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, scan, band) ; swath_data:coordinates = "lon lat" ;
Another example of the Multiband Swath encoding with alphanumeric-valued band coordinate because numerical information may not always be sufficient to distinguish between spectral bands.
dimensions: time = UNLIMITED ; scan = 1024 ; num_band = 8 ; variables: string band(num_band) ; band:standard_name = "sensor_band_identifier" ; float lat(time, scan) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, scan) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, scan, num_band) ; swath_data:coordinates = "lon lat band" ;
The previous encoding is for swath data where a single time instance applies to all across-track observations belonging to one along-track scanning cycle. Single time instance can also apply to a number of successive along-track scanning cycles, for example, when two-dimensional imaging sensors acquire swath data as a multiband image.
dimensions: time = 1 ; nrows = 2048 ; (1) ncols = 2048 ; (2) band = 10 ; variables: float band(band) ; band:standard_name = "sensor_band_central_radiation_wavelength" ; band:units = "μm" ; float lat(time, nrows, ncols) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, nrows, ncols) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, nrows, ncols, band) ; swath_data:coordinates = "lon lat" ;
-
Number of rows of the two-dimensional imaging sensor.
-
Number of columns of the two-dimensional imaging sensor.
The same encoding is applicable to swath data from hyperspectral sounding instruments which make observations arranged into a grid, typically 2-by-2 or 3-by-3 (see Figure 1). Such grouping of the observations comprises one field-of-regard (FOR).
1
through 9
. Observations are made from all fields-of-view independently. Depending on the viewing geometry for each FOR the geospatial extent and relative position varies for every field-of-view.The following example is identical to the previous one except for two dimensions with changed names.
dimensions: time = 50 ; FOR = 45 ; (1) obs = 9 ; (2) band = 1305 ; variables: float band(band) ; band:standard_name = "sensor_band_central_radiation_wavelength" ; band:units = "μm" ; float lat(time, FOR, obs) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, FOR, obs) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, FOR, obs, band) ; swath_data:coordinates = "lon lat" ;
-
The number of fields-of-regard in one across-track scan.
-
The number of observations within one field-of-regard.
An interesting variation in the above encoding would be if the FOR
and obs
dimensions exchanged places in the ordering, e.g. (time, FOR, obs, …)
→ (time, obs, FOR, …)
. The latter ordering corresponds to the spatial arrangement of the fields-of-regard and their observations: FOR
match the columns and obs
match the rows of a two-dimensional imaging sensor. In other words: FOR
→ ncols
and obs
→ nrows
.
Very common encoding used for storing 2D geophysical parameters.
dimensions: time = 512 ; scan = 1024 ; variables: double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float lat(time, scan) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, scan) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; float swath_data(time, scan) ; swath_data:coordinates = "lon lat" ;
For completeness, the example below uses along- and across-track dimensions instead.
dimensions: atrack = 512 ; xtrack = 1024 ; variables: double time(atrack) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float lat(atrack, xtrack) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(atrack, xtrack) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; float swath_data(atrack, xtrack) ; swath_data:coordinates = "time lon lat" ; (1)
-
time
is an auxiliary coordinate (because it is defined with theatrack
dimension) and must be listed in thecoordinates
attribute.
This encoding is the geophysical analog of the Multiband Image encoding.
dimensions: time = 1 ; nrows = 1024 ; ncols = 3600 ; variables: float lat(time, nrows, ncols) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, nrows, ncols) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, nrows, ncols) ; swath_data:coordinates = "lon lat" ;
dimensions: time = UNLIMITED ; FOR = 30 ; obs = 9 ; variables: double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float lat(time, FOR, obs) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, FOR, obs) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; float swath_data(time, FOR, obs) ; swath_data:coordinates = "lon lat" ;
This encoding consists of the Swath encoding with a vertical coordinate. All types of vertical coordinates are allowed.
dimensions: time = UNLIMITED ; scan = 512 ; press = 15 ; variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, scan) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, scan) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, scan, press) ; swath_data:coordinates = "lon lat" ;
dimensions: atrack = 512 ; xtrack = 1024 ; press = 15 ; variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; double time(atrack) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float lat(atrack, xtrack) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(atrack, xtrack) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; float swath_data(atrack, xtrack, press) ; swath_data:coordinates = "time lon lat" ;
An interesting trait of this encoding is the presence of a spectral coordinate when storing geophysical parameters.
dimensions: time = UNLIMITED ; scan = 512 ; band = 5 ; press = 15 ; variables: float band(band) ; band:standard_name = "sensor_band_central_radiation_wavenumber" ; band:units = "cm-1" ; float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, scan) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, scan) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, scan, press, band) ; swath_data:coordinates = "lon lat" ;
This encoding consists of the the Image Swath with an altitude coordinate.
dimensions: time = 1 ; nrows = 1024 ; ncols = 3600 ; press = 100 ; variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, nrows, ncols) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, nrows, ncols) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, nrows, ncols, press) ; swath_data:coordinates = "lon lat" ;
As in the few previous encoding examples, assuming that nrows
represents fields-of-regard (FOR) and ncols
represents observations (obs
), the above encoding can also serve for storing profiles from hyperspectral sounders. The following example illustrates this:
dimensions: time = 1 ; FOR = 1024 ; obs = 3600 ; press = 100 ; variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, FOR, obs) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, FOR, obs) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, FOR, obs, press) ; swath_data:coordinates = "lon lat" ;
There are two more ways to encode swath data with fields-of-regard and their observations. The differences between these encodings are:
-
How much latitude/longitude data are provided: for all observations in each field-of-regard, or just for each field-of-regard as a whole.
-
A two-dimensional layout of observations within the field-of-regard.
dimensions: time = 10 ; FOR = 30 ; (1) press = 15 ; obs_atrack = 3 ; (2) obs_xtrack = 3 ; (3) variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, FOR, obs_atrack, obs_xtrack) ; (4) lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, FOR, obs_atrack, obs_xtrack) ; (4) lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, FOR, obs_atrack, obs_xtrack, press) ; swath_data:coordinates = "lon lat" ;
-
Number of fields-of-regard in one across-track scan.
-
Along-track (row) dimension of the observations matrix.
-
Across-track (column) dimension of the observations matrix.
-
Latitude and longitude for all observations in every field-of-regard.
dimensions: time = 10 ; FOR = 30 ; press = 15 ; obs_atrack = 3 ; obs_xtrack = 3 ; variables: short obs_atrack(obs_atrack): (1) obs_atrack:long_name = "Along-track observation ordinal number" ; short obs_xtrack(obs_xtrack): (1) obs_xtrack:long_name = "Across-track observation ordinal number" ; float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; float lat(time, FOR) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; float lon(time, FOR) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; double time(time) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float swath_data(time, FOR, obs_atrack, obs_xtrack, press) ; swath_data:coordinates = "lon lat" ;
-
obs_atrack
andobs_xtrack
are coordinates now compared to the previous example because thelat
andlon
auxiliary coordinates do not depend on them.
The encodings so far represented observations as geolocated points. Points in mathematics represent geometric entities with no length, area, or volume, i.e. they are zero-dimensional. Real observations, however, have finite geospatial extent. Each of the swath encodings can be augmented with boundary variables to describe the geospatial extent of each observation. This approach is appropriate if:
-
Observation’s geospatial extent can be represented with a single geopolygon with no holes; and
-
the number of vertices for all such geopolygons is the same.
To illustrate the concept, boundary variables are added to the Profile encoding example:
dimensions: atrack = 512 ; xtrack = 1024 ; press = 15 ; vertices = 4 ; (1) variables: float press(press) ; press:standard_name = "air_pressure" ; press:units = "Pa" ; press:positive = "up" ; double time(atrack) ; time:standard_name = "time" ; time:units = "<units> since <datetime string>" ; time:calendar = "gregorian" ; float lat(atrack, xtrack) ; lat:standard_name = "latitude" ; lat:units = "degrees_north" ; lat:bounds = "lat_vertex" ; (2) float lon(atrack, xtrack) ; lon:standard_name = "longitude" ; lon:units = "degrees_east" ; lon:bounds = "lon_vertex" ; (2) float lat_vertex(atrack, xtrack, vertices) ; (3) float lon_vertex(atrack, xtrack, vertices) ; (3) float swath_data(atrack, xtrack, press) ; swath_data:coordinates = "time lon lat" ;
-
The dimension declares the number of geopolygon vertices.
-
Boundary variables,
lat_vertex
andlon_vertex
, are associated with their respective coordinates. -
The boundary variables.
Boundary variables have one more dimension, the fastest-varying one, than their respective coordinates. In the example above they link an observation (atrack
, xtrack
) with its geopolygon specified by the vertices (lat_vertex
(atrack
, xtrack
, n
), lon_vertex
(atrack
, xtrack
, n
)), for n
=0
,…, vertices
-1. The geolocation (lat
(atrack
, xtrack
), lon
(atrack
, xtrack
)) must be contained within this geopolygon. The vertices must be ordered counterclockwise when viewed in the lon
-lat
plane from above.
This kind of hierarchy is created using the grouping feature of the netCDF Enhanced Data Model and is colloquially known as groups in files. Since the current CF convention is not based on the Enhanced Data Model such files are not strictly CF compliant. However, groups are present in many swath data files.
The swath data encodings presented here are deliberately group-agnostic although that does not mean the use of groups is prohibited. A proposal on group hierarchies in the CF convention is being developed as part of the same project as this proposal. The most relevant aspect of that proposal for swath data encodings is the set of rules describing how to locate variables referenced in CF attributes like coordinates
. It is enough to use just variable names in such attributes for files without groups but this practice is ambiguous in the presence of groups as there could be more than one same-named variable. The group proposal describes how to handle all such cases. The following example illustrates two possible options for referencing variables in the swath encodings: using their names, or with the complete hierarchy starting from the top group.
Variables are located in separate groups based on their category: scientific, geolocation, quality information.
dimensions: vertex = 4 ; time = 392 ; band = 4 ; xtrack = 35 ; variables: double time(time) ; :standard_name = "time" ; :units = "<units> since <datetime string>" ; :calendar = "gregorian" float band(band) ; :standard_name = "sensor_band_central_radiation_wavelength" ; :units = "nm" ; group: ancillary { variables: float quality(time, xtrack, band) ; :coordinates = "/time /geolocation/lat /geolocation/lon /band" ; (1) } group: geolocation { variables: float lat_vertex(time, xtrack, vertex) ; float lon_vertex(time, xtrack, vertex) ; float lat(time, xtrack) ; :standard_name = "latitude" ; :units = "degrees_north" ; :bounds = "/geolocation/lat_vertex" ; (1) float lon(time, xtrack) ; :standard_name = "longitude" ; :units = "degrees_east" ; :bounds = "/geolocation/lon_vertex" ; } group: science { variables: float science_data(time, xtrack) ; :coordinates = "/time /geolocation/lat /geolocation/lon" ; :units = "K" ; :ancillary_variables = "/ancillary/quality" ; (1) float radiance(time, xtrack, band) ; :coordinates = "/time /geolocation/lat /geolocation/lon /band" ; :units = "W sr m−2" ; :ancillary_variables = "/ancillary/quality" ; }
-
Variable reference starting with a
/
represents the complete hierarchical path to that variable.
All coordinate variables (temporal, spectral, geospatial) are located in a parent group of where other variables are.
dimensions: vertex = 4 ; time = 392 ; band = 4 ; xtrack = 35 ; variables: double time(time) ; :standard_name = "time" ; :units = "<units> since <datetime string>" ; :calendar = "gregorian" float band(band) ; :standard_name = "sensor_band_central_radiation_wavelength" ; :units = "nm" ; float lat_vertex(time, xtrack, vertex) ; float lon_vertex(time, xtrack, vertex) ; float lat(time, xtrack) ; :standard_name = "latitude" ; :units = "degrees_north" ; :bounds = "lat_vertex" ; float lon(time, xtrack) ; :standard_name = "longitude" ; :units = "degrees_east" ; :bounds = "lon_vertex" ; group: ancillary { variables: float quality(time, xtrack, band) ; :coordinates = "time lat lon band" ; (1) } group: science { variables: float science_data(time, xtrack) ; :coordinates = "time lat lon" ; :units = "K" ; :ancillary_variables = "/ancillary/quality" ; (2) float radiance(time, xtrack, band) ; :coordinates = "time lat lon band" ; :units = "W sr m−2" ; :ancillary_variables = "/ancillary/quality" ; }
-
Variable references without any
/
character require search up the ancestral group hierarchy to locate the first variable of the same name. -
It is allowed to mix different methods for referencing variables in the same file.
The following examples are from a variety of satellite swath data stored in the netCDF, HDF4, and HDF5 file formats. This is to illustrate the variety of encodings for swath data, which on one hand provides an impetus to define a CF standard, but on the other hand exemplify the difficulty in getting all satellite data to conform to a standard.
The Moderate Resolution Imaging Spectroradiometer (MODIS) is a key instrument aboard the Terra (originally known as EOS AM-1) and Aqua (originally known as EOS PM-1) satellites. [1]
CF non-compliant attributes:
-
Groups are used in variables and geolocation fields
-
Non-standard dimension names (
2*nscans
) -
Latitude and longitude variables lack
standard_name
attribute
group: MODIS_SWATH_Type_L1B { dimensions: 2*nscans = 406 ; 1KM_geo_dim = 271 ; variables: int 10*nscans(2*nscans=406) ; :_DimensionMap = "" ; int Max_EV_frames(1KM_geo_dim=271) ; :_DimensionMap = "" ; group: Geolocation_Fields { variables: float Latitude(2*nscans=406, 1KM_geo_dim=271) ; :units = "degrees_north" ; :valid_range = -90.0f, 90.0f ; // float :_FillValue = -999.0f ; // float :line_numbers = "3,8" ; :frame_numbers = "3,8,13,..." ; float Longitude(2*nscans=406, 1KM_geo_dim=271) ; :units = "degrees_east" ; :valid_range = -180.0f, 180.0f ; // float :_FillValue = -999.0f ; // float :line_numbers = "3,8" ; :frame_numbers = "3,8,13,..." ; } }
The Tropical Rainfall Measuring Mission (TRMM), a joint mission of NASA and the Japan Aerospace Exploration Agency, was launched in 1997 to study rainfall for weather and climate research. The satellite was retired on 8 April 2015. [2]
CF non-compliant attributes:
-
Latitude and longitude variables lack
standard_name
attribute. -
Non-physical values of the
units
attributes:std_latitude
,std_longitude
.
dimensions: line = 2939 ; samp_lo = 104 ; samp_hi = 208 ; variables: short lat_hi(line, samp_hi) ; lat_hi:units = "std_latitude" ; lat_hi:missing_value = -32768s ; lat_hi:valid_min = -9000s ; lat_hi:valid_max = 9000s ; lat_hi:scale_factor = 0.01 ; short lat_lo(line, samp_lo) ; lat_lo:units = "std_latitude" ; lat_lo:missing_value = -32768s ; lat_lo:valid_min = -9000s ; lat_lo:valid_max = 9000s ; lat_lo:scale_factor = 0.01 ; short lon_hi(line, samp_hi) ; lon_hi:units = "std_longitude" ; lon_hi:missing_value = -32768s ; lon_hi:valid_min = -18000s ; lon_hi:valid_max = 18000s ; lon_hi:scale_factor = 0.01 ; short lon_lo(line, samp_lo) ; lon_lo:units = "std_longitude" ; lon_lo:missing_value = -32768s ; lon_lo:valid_min = -18000s ; lon_lo:valid_max = 18000s ; lon_lo:scale_factor = 0.01 ;
The Special Sensor Microwave Imager (SSM/I) Sensor is carried aboard Defense Meteorological Satellite Program (DMSP) satellites DMSP F-8, DMSP F-10, DMSP F-11, DMSP F-12, and DMSP F-13. [3]
CF non-compliant attributes:
-
Latitude and longitude variables lack
standard_name
attribute. -
Non-physical values of the
units
attributes:std_latitude
,std_longitude
.
dimensions: miline_hi = 1124 ; misamp_hi = 128 ; miline_lo = 562 ; misamp_lo = 64 ; variables: short lat_hi(miline_hi, misamp_hi) ; lat_hi:units = "std_latitude" ; lat_hi:missing_value = -32768s ; lat_hi:valid_min = -32768s ; lat_hi:valid_max = 32767s ; lat_hi:scale_factor = 0.01 ; short lat_lo(miline_lo, misamp_lo) ; lat_lo:units = "std_latitude" ; lat_lo:missing_value = -32768s ; lat_lo:valid_min = -32768s ; lat_lo:valid_max = 32767s ; lat_lo:scale_factor = 0.01 ; short lon_hi(miline_hi, misamp_hi) ; lon_hi:units = "std_longitude" ; lon_hi:missing_value = -32768s ; lon_hi:valid_min = -32768s ; lon_hi:valid_max = 32767s ; lon_hi:scale_factor = 0.01 ; short lon_lo(miline_lo, misamp_lo) ; lon_lo:units = "std_longitude" ; lon_lo:missing_value = -32768s ; lon_lo:valid_min = -32768s ; lon_lo:valid_max = 32767s ; lon_lo:scale_factor = 0.01 ;
The adoption of this document relies on its quality and applicability which greatly depends on community feedback. The document is hosted in a GitHub repository and its most up-to-date version can be viewed here. Comments or suggestions are welcome either as issues, pull requests, or emails to the authors.
The flowchart below (Figure 2) describes the process for identifying the proposed swath data encodings. It starts from a netCDF variable that is already assumed to represent a swath data parameter. The variable’s rank and the type and rank of its coordinates are used to determine the actual encoding type.
Release | Description |
---|---|
DRAFT/2017-05-16 |
Initial version. |
DRAFT/2017-08-31 |
|
FINAL DRAFT/2018-03-01 |
|
FINAL DRAFT/2018-04-27 |
|
FINAL DRAFT/2018-06-19 |
|