Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more metadata from Sentinel-1 Prodict Specification #25

Merged
merged 4 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 52 additions & 14 deletions xarray_sentinel/conventions.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,61 @@
"""CF representation of metadata according to
Sentinel-1 Product Specification: S1-RS-MDA-52-7441, DI-MPC-PB, MPC-0240, 3/7, 27/02/2020 See:
https://sentinel.esa.int/documents/247904/1877131/Sentinel-1-Product-Specification
"""

import xarray as xr

from . import __version__

GROUP_ATTRIBUTES = {
"orbit": {
"title": "Orbit information used by the IPF during processing",
"comment": (
"The dataset contains a sets of orbit state vectors that are updated along azimuth."
" The values represent the interpolated values used by the IPF"
" and are derived from the sub-commutated ancillary data from the ISPs"
" or from an input auxiliary orbit file"
),
},
"attitude": {
"title": "Attitude information used by the IPF during processing",
"comment": (
"The dataset contains a sets of attitude data records that are updated along azimuth."
" The values represent the interpolated values used by the IPF"
" and are derived from the sub-commutated ancillary data from the ISPs"
" or from an input auxiliary orbit file"
),
},
"gcp": {
"title": "Geolocation grid",
"comment": (
"The dataset contains geolocation grid point entries for each line/pixel"
" combination based on a configured resolution."
" The list contains an entry for each update made along azimuth"
),
},
}

VARIABLE_ATTRIBUTES = {
"azimuth_time": {"long_name": "azimuth time", "standard_name": "time"},
"azimuth_time": {"long_name": "zero Doppler azimuth time", "standard_name": "time"},
# NOTE: `slant_range_time` is not expressed as `np.timedelta64[ns]` in order to keep enough
# accuracy for interferometric processing, i.e. c * 1ns / 2 ~= 15cm.
"slant_range_time": {"units": "s", "long_name": "slant range time / two-way delay"},
"latitude": {"units": "degrees_north"},
"longitude": {"units": "degrees_east"},
"height": {"units": "m"},
"incidenceAngle": {"units": "degrees"},
"elevationAngle": {"units": "degrees"},
"q0": {"units": "1"},
"q1": {"units": "1"},
"q2": {"units": "1"},
"q3": {"units": "1"},
"roll": {"units": "degrees"},
"pitch": {"units": "degrees"},
"yaw": {"units": "degrees"},
"latitude": {"units": "degrees_north", "long_name": "geodetic latitude"},
"longitude": {"units": "degrees_east", "long_name": "geodetic longitude"},
"height": {"units": "m", "long_name": "height above sea level"},
"incidenceAngle": {"units": "°", "long_name": "incidence angle"},
"elevationAngle": {"units": "°", "long_name": "elevation angle"},
"q0": {"units": "1", "long_name": "Q0 attitude quaternion"},
"q1": {"units": "1", "long_name": "Q1 attitude quaternion"},
"q2": {"units": "1", "long_name": "Q2 attitude quaternion"},
"q3": {"units": "1", "long_name": "Q3 attitude quaternion"},
"roll": {"units": "°", "long_name": "platform roll"},
"pitch": {"units": "°", "long_name": "platform pitch"},
"yaw": {"units": "°", "long_name": "platform yaw"},
"wx": {"units": "° s-1", "long_name": "X component of angular velocity vector"},
"wy": {"units": "° s-1", "long_name": "Y component of angular velocity vector"},
"wz": {"units": "° s-1", "long_name": "Z component of angular velocity vector"},
"time": {"standard_name": "time"},
"x": {"units": "m", "long_name": "position x"},
"y": {"units": "m", "long_name": "position y"},
Expand All @@ -29,10 +66,11 @@
}


def update_attributes(ds: xr.Dataset) -> xr.Dataset:
def update_attributes(ds: xr.Dataset, group: str = "") -> xr.Dataset:
# NOTE: keep the version in sync with the capabilities of CF compliance checkers
ds.attrs["Conventions"] = "CF-1.7"
ds.attrs["history"] = f"created by xarray_sentinel-{__version__}"
ds.attrs.update(GROUP_ATTRIBUTES.get(group, {})) # type: ignore
for var in ds.variables:
attrs = VARIABLE_ATTRIBUTES.get(str(var), {})
ds.variables[var].attrs.update(attrs) # type: ignore
Expand Down
6 changes: 3 additions & 3 deletions xarray_sentinel/sentinel1.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def open_gcp_dataset(annotation_path: esa_safe.PathType) -> xr.Dataset:
"slant_range_time": sorted(slant_range_time),
},
)
conventions.update_attributes(ds)
conventions.update_attributes(ds, group="gcp")
return ds


Expand All @@ -66,7 +66,7 @@ def open_attitude_dataset(annotation_path: esa_safe.PathType) -> xr.Dataset:
data_vars=data_vars, # type: ignore
coords={"time": [np.datetime64(dt) for dt in time]},
)
ds = conventions.update_attributes(ds)
ds = conventions.update_attributes(ds, group="attitude")
return ds


Expand Down Expand Up @@ -102,7 +102,7 @@ def open_orbit_dataset(annotation_path: esa_safe.PathType) -> xr.Dataset:
attrs=attrs, # type: ignore
coords={"time": [np.datetime64(dt) for dt in time]},
)
ds = conventions.update_attributes(ds)
ds = conventions.update_attributes(ds, group="orbit")
return ds


Expand Down