Requesting multiple tiles via a single request (no mosaicking)

Hi,

I’m trying to request all Sentinel-1 IW ASC tiles for a given polygon within a given time interval (i.e. no mosaicking intended).

My evalscript:

evalscript = """
    //VERSION=3
    function setup() {
        return {
            input: ["VV"],
            output: [{id:"VV", bands: 1, sampleType: "FLOAT32"}],
            mosaicking: "TILE",
        }
    }

    function evaluatePixel(samples) {
      return [toDb(samples.VV)]
    }

    function toDb(linear) {
        return 10 * Math.log(linear) / Math.LN10
    }
"""

And my request:

request = sentinelhub.SentinelHubRequest(
    evalscript=evalscript,
    input_data=[
        sentinelhub.SentinelHubRequest.input_data(
            data_collection=sentinelhub.DataCollection.SENTINEL1_IW_ASC,
            time_interval=('2022-03-15T00:00:00', '2022-04-24T23:59:59.999999'),
            other_args={
                            "dataFilter": {
                                "resolution": "HIGH"
                            },
                            "processing": {
                                "orthorectify": "true",
                                "demInstance": "COPERNICUS",
                                "backCoeff": "SIGMA0_ELLIPSOID",
                                "speckleFilter": {
                                    "type": "LEE",
                                    "windowSizeX": 3,
                                    "windowSizeY": 3
                                }
                            }
                        }
        ),
    ],
    responses=[sentinelhub.SentinelHubRequest.output_response('VV', sentinelhub.MimeType.TIFF)],
    bbox=search_bbox,
    size=[51, 49],
    config=config
)

result = request.get_data()

Unfortunately, the result is a numpy array filled with NaN values.

The above request works (i.e. returns a non-NaN array) if mosaicking: "SIMPLE" is used instead of TILE. However, this is not optimal because the result is a mosaic of all the tiles available for the polygon between the given dates and I need to request all tiles for further processing.

My initial solution was to check dates when tiles were available for that polygon (using SentinelHubCatalog.search()) and put the above code inside a for-loop to request tiles for each date individually. But such solution is very costly in terms of requests (not necessarily PUs).

  1. Is there a way to request all tiles between given dates using a single request?
  2. Will such a request cost 1 request from my quota even though I requested tiles from multiple days?
  3. Is it possible to somehow assign a date to each tile so I know which date the tile was collected?

Thanks!

Hi, to answer your questions:

  1. Yes, you can request multiple dates in a single request.
  2. This counts as a single request, although of course you will be utilising more PUs as you will be processing more data.
  3. You can also output a json file that will contain the timestamps of the tiles that you request as well as other metadata if desired.

To show you how to do this, I’ve provided the following evalscript that will allow you to achieve this.

//VERSION=3

function setup() {
  return {
    input: ["VV", "dataMask"],
    output: [{
      id: "VV",
      bands: 1,
      sampleType: "FLOAT32"}],
    mosaicking: "ORBIT"
  };
}

var timestamps = []

function updateOutputMetadata(scenes, inputMetadata, outputMetadata){
    outputMetadata.userData = {
          "Dates":  [...new Set(timestamps)]
    }
}

function preProcessScenes (collections) {
  // Sort scenes by dateFrom in ascending order
  collections.scenes.orbits.sort(function (s1, s2) {
    var date1 = new Date(s1.dateFrom)
    var date2 = new Date(s2.dateFrom)
    return date1 - date2
  })
  return collections
}

function updateOutput (outputs, collections) {
  outputs.VV.bands = collections.scenes.length
}
function toDb(linear) {
        return 10 * Math.log(linear) / Math.LN10
    }

function evaluatePixel(samples, scenes) {

  var VV_bands = []

  for (let i = 0; i < scenes.length; i++){
    if (samples[i].dataMask === 1){
      VV_bands.push(toDb(samples[i].VV))
    } else {
      // No data = - 9999
      VV_bands.push(-9999)
    }
    timestamps.push(JSON.stringify(scenes[i].date))
  }
  return {
    VV: VV_bands
  }
}

This script works with Orbit mosaicking and outputs a band for each acquisition in the requested time period. In the tar file is also a json file that contains the dates of the acquisition in each band.

I hope this helps to answers your questions. More than happy to help clarify further if required.

1 Like

Thanks a lot! This works great.

I was able to retrieve the timestamps by adding SentinelHubRequest.output_response('userdata', MimeType.JSON) to the responses list.

In addition to the acquisition dates, is it possible to include spatial extent (i.e. transform) for each tile? I need the transforms to be able to modify those tiles further using rasterio etc. I’ve edited updateOutputMetadata() function to include metadata about each scene

function updateOutputMetadata(scenes, inputMetadata, outputMetadata){
        outputMetadata.userData = {
              "dates":  [...new Set(timestamps)],
              "info": [scenes.orbits]
        }
}

But info includes only IDs of the tiles used to generate each scene. I could use those IDs to fetch more detailed metadata (including the transform) using SentinelHubCatalog but I was wondering if there was an easier way to achieve this.

I noticed that there are dataGeometry and dataEnvelope fields but apparently they are “optional properties, added only when requested” (https://docs.sentinel-hub.com/api/latest/evalscript/v3/#scenes).

Modifying the updateOutputMetadata() function further:

function updateOutputMetadata(scenes, inputMetadata, outputMetadata){
    outputMetadata.userData = {
          "dates":  [...new Set(timestamps)],
          "info": [scenes.orbits[0].tiles[0].dataEnvelope]
    }
}

Returns an empty info array. Am I missing something?

Hi,

I’m happy that the evalscript is useful to you. To learn more about the metadata you can access through the evalscript I would recommend reading into the documentation:

  • you can find out more in general here
  • and more specifically for scenes here

You will see that different metadata fields are available depending on the mosaicking approach you use. Using TILE mosaicking should give you access to the dataGeometry metadata field.

Let us know how you get on!