Sentinel-1 metadata

Hi, can you please advise on how to get the S1 metadata returned using SentinelHubInputTask? From this question I tried setting mosaicking to TILE, but that gives the error “TILE is not a valid MosaickingOrder”. Specifically, I’m looking for the tile id in the scenes object,

s1_aux_args = dict(
    dataFilter = {'acquisitionMode': 'IW'},
    processing = {
        'backCoeff': 'GAMMA0_TERRAIN',
        'orthorectify': True,
        "speckleFilter": {
            "type": "LEE",
            "windowSizeX": 5,
            "windowSizeY": 5 
            }
    }
    
    )

add_data = SentinelHubInputTask(
    bands_feature=(FeatureType.DATA, "BANDS"),
    bands=  ["VV", "VH"],
    resolution=20,
    time_difference=datetime.timedelta(minutes=120),
    data_collection=DataCollection.SENTINEL1_IW,
    mosaicking_order='TILE',
    aux_request_args=s1_aux_args,
    additional_data = [(FeatureType.DATA, "localIncidenceAngle")],
    max_threads=5,
)

Hi @sdtaylor!

Welcome to the SH Forum! Let’s look at your issue. You mention that you’re interested in having tile ids from the scenes object. I see you’re also interested in the bands (VV, VH) as well as the localIncidenceAngle. For the latter I confirm that the aux settings are correct in order to obtain them.

The first issue I notice is that you are setting the value of mosaicking_order, which just specifies how the order is taken (leastCC, mostRecent, or leastRecent) and has nothing to do with setting the mosaicing method (SIMPLE, ORBIT, or TILE). This is something you have to do in the evalscript itself, which means that the SentinelHubInputTask is not the appropriate task in this case. Fortunately, it is also possible to use SentinelHubEvalscriptTask, which is the appropriate one here.

The parameters of the function are a bit different. You can check them out here: eo-learn/sentinelhub_process.py at master · sentinel-hub/eo-learn · GitHub

You see that you have to provide your own evalscript and the output features, which is what we want.

Let’s first build the evalscript. From the evalscript point-of-view, the bands VV, VH and localIncidenceAngle are all the same, we just need to set the aux settings so that the latter is available. In the evalscript we will set the mosaicking to TILE, so that the input samples/scenes are split per tile. Then we have to decide which value of the bands to take. Here I will simply just take the first valid value of the band, according to the dataMask, otherwise return 0 if no valid scenes are found. Due to the way the SentinelHubEvalscriptTask is constructed, we have to specify the outputs of the evalscript, so that they can later be mapped to the features in the EOPatch. The most relevant part of the evalscript below is the bottom part, where we use the updateOutputMetadata function to update the userdata dictionary by adding all of the scenes.tiles information in it. This can be customized to your liking any way you want.

evalscript = """
//VERSION=3
function setup() {
  return {
    mosaicking: Mosaicking.TILE,
    input: ["VV", "VH", "localIncidenceAngle", "dataMask"],
    output: [
      {
        id: "BANDS",
        bands: 2,
        sampleType: "FLOAT32"
      },
      {
        id: "localIncidenceAngle",
        bands: 1,
        sampleType: "UINT8"
      }
    ]
  }
}

function evaluatePixel(samples, scenes, inputMetadata, customData, outputMetadata) {
  // Take first valid scene data
  for (i = 0; i < samples.length; i++) {
    var sample = samples[i]
    if (sample.dataMask == 1){
      return {
        "BANDS": [sample.VV, sample.VH], 
        "localIncidenceAngle": [sample.localIncidenceAngle]
      };
    }
  }
  
  return {
    "BANDS": [0, 0],
    "localIncidenceAngle": [0]
  };
}

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
  outputMetadata.userData = {
    "tiles": scenes.tiles
  }
}
"""

Now that we have the evalscript ready, we can build the EOTask in the similar way as you did above. I didn’t change the s1_aux_args settings.

add_data = SentinelHubEvalscriptTask(
    features=[(FeatureType.DATA, "BANDS"), (FeatureType.DATA, "localIncidenceAngle"), (FeatureType.META_INFO, 'userdata')],
    evalscript=evalscript,
    data_collection=DataCollection.SENTINEL1_IW,
    resolution=20,
    time_difference=datetime.timedelta(minutes=120),
    aux_request_args=s1_aux_args,
    max_threads=5,
)

Basically youjust need to specify the features and the evalscript, where the meta info had to be specified as the userdata META_INFO feature, so that the json output is added to the meta info dictionary.

After running this on an example geometry and time frame, you get the following output:

geojson = {"type":"Polygon","coordinates":[[[12.429314,41.860868],[12.429314,41.934466],[12.527847,41.934466],[12.527847,41.860868],[12.429314,41.860868]]]}
bbox = Geometry.from_geojson(geojson).bbox
time_interval = ("2022-05-24", "2022-06-04")

eop = add_data(bbox=bbox, time_interval=time_interval)
EOPatch(
  data={
    BANDS: numpy.ndarray(shape=(3, 397, 421, 2), dtype=float32)
    localIncidenceAngle: numpy.ndarray(shape=(3, 397, 421, 1), dtype=uint8)
  }
  meta_info={
    size_x: 421
    size_y: 397
    time_difference: 7200.0
    time_interval: ('2022-05-24T00:00:00', '2022-06-04T23:59:59')
    userdata: <class 'list'>, length=3
  }
  bbox=BBox(((12.429314, 41.860868), (12.527847, 41.934466)), crs=CRS('4326'))
  timestamp=[datetime.datetime(2022, 5, 27, 5, 20, 5), ..., datetime.datetime(2022, 6, 3, 5, 11, 54)], length=3
)

and the tile info for the first timestamp in the EOPatch can be accessed as eop.meta_info['userdata'][0]['tiles']

[
  {
    'date': '2022-05-27T05:20:05Z',
    'shId': 2674115,
    'tileOriginalId': 'S1A_IW_GRDH_1SDV_20220527T052005_20220527T052030_043392_052E88_57D9',
    '__idx': 0,
    'dataPath': 's3://sentinel-s1-l1c/GRD/2022/5/27/IW/DV/S1A_IW_GRDH_1SDV_20220527T052005_20220527T052030_043392_052E88_57D9'
  }
]

Let me know if there is anything else left unresolved!

Cheers,
Matic

1 Like