I finally understood the issue, which came from the EOPF product itself. The ground_range coordinates of the LUTs contain wrong values and the workaround consist in interpolating using the two other corresponding dimensions called line and pixel.
I reported the issue on the EOPF GitLab here: S1 L1 mapping quality group (#887) · Issues · EOPF CPM / EOPF Core Python Modules · GitLab
The working code can be found below:
import xarray as xr
import numpy as np
import rioxarray
import matplotlib.pyplot as plt
grd_path = "https://objects.eodc.eu/e05ab01a9d56408d82ac32d69a5aae2a:notebook-data/tutorial_data/cpm_v262/S1B_IW_GRDH_1SDV_20170503T173207_20170503T173232_005437_00987B_1A41.zarr"
dt = xr.open_datatree(grd_path, engine="zarr", chunks="auto")
group_VH = [x for x in dt.children if "VH" in x][0]
grd_vh = dt[group_VH].measurements.to_dataset().rename({"grd": "vh"})
sigma_lut = dt[group_VH].quality.calibration.sigma_nought
sigma_lut_line_pixel = xr.DataArray(
data=sigma_lut.data,
dims=["line", "pixel"],
coords=dict(
line=(["line"], sigma_lut.line.values),
pixel=(["pixel"], sigma_lut.pixel.values),
),
)
grd_vh_line_pixel = xr.DataArray(
data=grd_vh.vh.data,
dims=["line", "pixel"],
coords=dict(
line=(["line"], grd_vh.vh.line.values),
pixel=(["pixel"], grd_vh.vh.pixel.values),
),
)
sigma_lut_interp_line_pixel = sigma_lut_line_pixel.interp_like(grd_vh_line_pixel,method="linear")
sigma_lut_interp = xr.DataArray(
data=sigma_lut_interp_line_pixel.data,
dims=["azimuth_time", "ground_range"],
coords=dict(
azimuth_time=(["azimuth_time"], grd_vh.vh.azimuth_time.values),
ground_range=(["ground_range"], grd_vh.vh.ground_range.values),
),
)
eopf_sigma_0_vh = ((abs(grd_vh.astype(np.float32)) ** 2) / (sigma_lut_interp**2)).vh.compute()
SNAP_sigma_0_path = "./S1B_IW_GRDH_1SDV_20170503T173207_20170503T173232_005437_00987B_1A41_Cal.tif"
SNAP_sigma_0_vh = rioxarray.open_rasterio(SNAP_sigma_0_path)[0]
SNAP_mean = SNAP_sigma_0_vh.mean().data
SNAP_median = SNAP_sigma_0_vh.median().data
EOPF_mean = eopf_sigma_0_vh.mean().data
EOPF_median = eopf_sigma_0_vh.median().data
print(f"SNAP sigma 0 vh mean: {SNAP_mean} median: {SNAP_median}")
print(f"EOPF sigma 0 vh mean: {EOPF_mean} median: {EOPF_median}")
fig, ax = plt.subplots(1,2,figsize=(16, 8))
eopf_sigma_0_vh.plot.hist(bins=300,xlim=(0,0.2),range=(0,0.2),ylim=(0,10000000),ax=ax[0])
ax[0].set_title("EOPF sigma 0")
SNAP_sigma_0_vh.plot.hist(bins=300,xlim=(0,0.2),range=(0,0.2),ylim=(0,10000000),ax=ax[1])
ax[1].set_title("SNAP sigma 0")
fig.tight_layout()
plt.show()
SNAP sigma 0 vh mean: 0.01803111843764782 median: 0.006793084088712931
EOPF sigma 0 vh mean: 0.01803111845179507 median: 0.006793084177165347