Tutorial for xarray-safe-s1#

xarray-safe-s1 is a xarray reader for Sentinel-1 SAFE files

[1]:
from safe_s1 import Sentinel1Reader, sentinel1_xml_mappings

Get a product path#

Here, we get the product path with xsar library, but this is optionnal

[2]:
# get test file. You can replace with an path to other SAFE
filename = sentinel1_xml_mappings.get_test_file('S1A_IW_GRDH_1SDV_20170907T103020_20170907T103045_018268_01EB76_Z010.SAFE')
filename
/home/docs/checkouts/readthedocs.org/user_builds/xarray-safe-s1/checkouts/latest/safe_s1/sentinel1_xml_mappings.py:105: UserWarning: Downloading https://cyclobs.ifremer.fr/static/sarwing_datarmor/xsardata/S1A_IW_GRDH_1SDV_20170907T103020_20170907T103045_018268_01EB76_Z010.SAFE.zip
  warnings.warn("Downloading %s" % file_url)
/home/docs/checkouts/readthedocs.org/user_builds/xarray-safe-s1/checkouts/latest/safe_s1/sentinel1_xml_mappings.py:107: UserWarning: Unzipping /tmp/S1A_IW_GRDH_1SDV_20170907T103020_20170907T103045_018268_01EB76_Z010.SAFE
  warnings.warn("Unzipping %s" % os.path.join(res_path, fname))
[2]:
'/tmp/S1A_IW_GRDH_1SDV_20170907T103020_20170907T103045_018268_01EB76_Z010.SAFE'

Open a product#

We apply Sentinel1Reader to open a Sentinel-1 product

[3]:
reader = Sentinel1Reader(name=filename)
reader
[3]:
<Sentinel1Reader single object>

Some properties permit to have informations about the product :

[4]:
# Type of product
reader.product
[4]:
'GRDH'
[5]:
# Mode
reader.dsid
[5]:
'IW'
[6]:
# Pixel line spacing (unit : meters)
reader.pixel_line_m
[6]:
<xarray.DataArray 'azimuthPixelSpacing' ()> Size: 8B
array(10.)
Attributes:
    source:   /product/imageAnnotation/imageInformation/azimuthPixelSpacing
[7]:
# Pixel sample spacing (unit : meters)
reader.pixel_sample_m
[7]:
<xarray.DataArray 'groundRangePixelSpacing' ()> Size: 8B
array(10.)
Attributes:
    source:   /product/imageAnnotation/imageInformation/rangePixelSpacing

Explore different files available#

In the reader object representation, we can see if the product is a multidataset or not. We can also access this information with the property multidataset :

[8]:
reader.multidataset
[8]:
False

Single dataset product#

Above, we can see that the product isn’t a multidataset, so we can access files like this :

[9]:
reader.files
[9]:
polarization dsid annotation measurement noise calibration
1 VV SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vv-20170907t103020-20170... measurement/s1a-iw-grd-vv-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vv-201... annotation/calibration/calibration-s1a-iw-grd-...
2 VH SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vh-20170907t103020-20170... measurement/s1a-iw-grd-vh-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vh-201... annotation/calibration/calibration-s1a-iw-grd-...

Multidataset product#

If the product is a multidataset, you must use the following property to see the safe files :

[10]:
reader.safe_files
[10]:
polarization dsid annotation measurement noise calibration
1 VV SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vv-20170907t103020-20170... measurement/s1a-iw-grd-vv-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vv-201... annotation/calibration/calibration-s1a-iw-grd-...
2 VH SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vh-20170907t103020-20170... measurement/s1a-iw-grd-vh-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vh-201... annotation/calibration/calibration-s1a-iw-grd-...

Or you can access the files of a subdataset applying the reader to a subdataset :

[11]:
# Access available datasets
datasets = reader.datasets_names
datasets
[11]:
['SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T103020_20170907T103045_018268_01EB76_Z010.SAFE:IW']
[12]:
# Instanciate a reader for a subdataset
reader = Sentinel1Reader(datasets[0])
[13]:
# Access the files of the subdataset
reader.files
[13]:
polarization dsid annotation measurement noise calibration
1 VV SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vv-20170907t103020-20170... measurement/s1a-iw-grd-vv-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vv-201... annotation/calibration/calibration-s1a-iw-grd-...
2 VH SENTINEL1_DS:/tmp/S1A_IW_GRDH_1SDV_20170907T10... annotation/s1a-iw-grd-vh-20170907t103020-20170... measurement/s1a-iw-grd-vh-20170907t103020-2017... annotation/calibration/noise-s1a-iw-grd-vh-201... annotation/calibration/calibration-s1a-iw-grd-...

Access the useful data#

It is expressed as a datatree

[14]:
data = reader.datatree
data
[14]:
<xarray.DatasetView> Size: 0B
Dimensions:  ()
Data variables:
    *empty*

In attributes (history) we can retrieve the files and xpaths used to get concerned data

Load digital numbers#

A function to load digital numbers with a specific resolution is also included in the reader. The function used is load_digital_number

Note : This function returns a tuple: resolution and digital numbers

[15]:
import rasterio
[16]:
# parameters
resampling = rasterio.enums.Resampling.rms
chunks = {'line': 5000, 'sample': 5000}
resolution = '1000m'
[17]:
dn = reader.load_digital_number(resolution=resolution, resampling=resampling, chunks=chunks)
dn
[17]:
(1000.0,
 <xarray.Dataset> Size: 171kB
 Dimensions:         (line: 167, sample: 251, pol: 2)
 Coordinates:
   * line            (line) float64 1kB 49.5 149.5 249.5 ... 1.655e+04 1.665e+04
   * sample          (sample) float64 2kB 49.5 149.5 ... 2.495e+04 2.505e+04
   * pol             (pol) object 16B 'VV' 'VH'
 Data variables:
     digital_number  (pol, line, sample) uint16 168kB dask.array<chunksize=(1, 167, 251), meta=np.ndarray>)

Some important functions used to build the datatree#

Calibration luts#

[18]:
reader.get_calibration_luts
[18]:
<xarray.Dataset> Size: 551kB
Dimensions:      (pol: 2, line: 27, sample: 631)
Coordinates:
  * line         (line) int64 216B 0 671 1342 2013 ... 15436 16107 16778 17449
  * sample       (sample) int64 5kB 0 40 80 120 160 ... 25080 25120 25160 25186
  * pol          (pol) object 16B 'VV' 'VH'
Data variables:
    sigma0_lut   (pol, line, sample) float64 273kB 662.0 661.7 ... 558.9 558.8
    gamma0_lut   (pol, line, sample) float64 273kB 613.4 613.1 ... 465.8 465.7
    azimuthTime  (pol, line) datetime64[ns] 432B 2017-09-07T10:30:20.936409 ....

Noise range luts#

[19]:
reader.get_noise_range_raw
[19]:
<xarray.Dataset> Size: 280kB
Dimensions:      (pol: 2, line: 27, sample: 634)
Coordinates:
  * line         (line) int64 216B 0 671 1342 2013 ... 15433 16104 16775 16777
  * sample       (sample) int64 5kB 0 40 80 120 160 ... 25068 25108 25148 25186
  * pol          (pol) object 16B 'VV' 'VH'
Data variables:
    noise_lut    (pol, line, sample) float64 274kB 1.641e+03 1.62e+03 ... 0.0
    azimuthTime  (pol, line) float64 432B nan nan nan nan ... nan nan nan nan
Attributes:
    history:  noise_lut_range_raw:\n  annotation/calibration/noise.xml:\n  - ...

Noise azimuth luts#

[20]:
reader.get_noise_azi_raw
[20]:
<xarray.Dataset> Size: 16B
Dimensions:       (pol: 2, swath: 0)
Coordinates:
  * swath         (swath) float64 0B
  * pol           (pol) object 16B 'VV' 'VH'
Data variables:
    line_start    (pol, swath) int64 0B
    line_stop     (pol, swath) int64 0B
    sample_start  (pol, swath) int64 0B
    sample_stop   (pol, swath) int64 0B
Attributes:
    history:  noise_lut_azi_raw_grd:\n  annotation/calibration/noise.xml:\n  ...

Geolocation grid#

The function used is geoloc, but it has a safety not to retrieve the data when it is already loaded. For this example, the data is already loaded so we must manually unlock the safety not to have a None result :

[21]:
# Unlock the safety
reader._dict['geolocationGrid'] = None
# Load the geolocation grid dataset
reader.geoloc
[21]:
<xarray.Dataset> Size: 12kB
Dimensions:         (line: 10, sample: 21)
Coordinates:
  * line            (line) int64 80B 0 2014 4028 6042 ... 14098 16112 16777
  * sample          (sample) int64 168B 0 1260 2520 3780 ... 22680 23940 25186
Data variables:
    longitude       (line, sample) float64 2kB -67.84 -67.96 ... -70.4 -70.51
    latitude        (line, sample) float64 2kB 20.73 20.75 20.77 ... 19.62 19.64
    height          (line, sample) float64 2kB 8.405e-05 8.058e-05 ... 3.478e-05
    azimuthTime     (line, sample) datetime64[ns] 2kB 2017-09-07T10:30:20.936...
    slantRangeTime  (line, sample) float64 2kB 0.005331 0.005375 ... 0.006382
    incidenceAngle  (line, sample) float64 2kB 30.82 31.7 32.57 ... 45.36 46.0
    elevationAngle  (line, sample) float64 2kB 27.5 28.27 29.02 ... 39.89 40.41
Attributes:
    history:  longitude:\n  annotation/s1a.xml:\n  - /product/geolocationGrid...

Orbit information#

[22]:
reader.orbit
[22]:
<xarray.Dataset> Size: 952B
Dimensions:     (time: 17)
Coordinates:
  * time        (time) datetime64[ns] 136B 2017-09-07T10:29:14.474905 ... 201...
Data variables:
    velocity_x  (time) float64 136B -116.7 -154.1 -191.4 ... -663.4 -698.6
    velocity_y  (time) float64 136B -3.433e+03 -3.368e+03 ... -2.342e+03
    velocity_z  (time) float64 136B -6.776e+03 -6.808e+03 ... -7.194e+03
    position_x  (time) float64 136B 2.892e+06 2.89e+06 ... 2.833e+06 2.826e+06
    position_y  (time) float64 136B -5.782e+06 -5.816e+06 ... -6.246e+06
    position_z  (time) float64 136B 2.869e+06 2.801e+06 ... 1.82e+06 1.748e+06
Attributes:
    orbit_pass:        Descending
    platform_heading:  -167.7668824808032
    frame:             Earth Fixed
    history:           orbit:\n  annotation/s1a.xml:\n  - //product/generalAn...