Distinguih between data from sentinel 2A to 2B

Hello,

is there any way to retrieve information regard image - if it is coming from sentinel-2A ot sentinel-2B?
currently I retrieve images from datacollection SENTINEL2_L2A , I would like to know for each image I retrieve if is from 2A or 2B.

how can I access this information?

Hi :slight_smile:

Yes you can retrieve this information using Catalog API.

In the example in the sentinelhub-py documentation you will see that the satellite (sentinel-2a or sentinel-2b) is given with the keyword platform.

This information is available both for L1C and L2A data.

Hope this is useful to you.

Hey William,
thank you for your fast answer!

I’m using sentinel hub request with fused data (sentinel +landsat). Is there any option to retrieve this data from there? or at least the sentinel image ID as seems like is needed for the catalog API.

This is my request:

        request = SentinelHubRequest(
            evalscript=evalscript,
            input_data=[
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.LANDSAT_OT_L2,
                    time_interval=(d,d),        
                    other_args = {"id":"LANDS89"}
                ),
                SentinelHubRequest.input_data(
                    data_collection=DataCollection.SENTINEL2_L2A,
                    time_interval=(d,d),        
                    other_args = {"id":"S2L2A"}
                ),
            ],
            responses=[
                SentinelHubRequest.output_response('default', MimeType.TIFF), 
            ],
            data_folder='fake/folder/',  
            bbox=bbox,
            size=bbox_size,
            config=config
        )
        
        response = request.get_data(save_data=False)
        

Hi :slight_smile:

Unfortunately, this information isn’t available through the evalscript, you would have to also using Catalog API in your python script to obtain this information.

For more information about the data that can be obtained in the evalscript you can read here.

What about some of the function mentioned here?
for example get_download_list(),get_url_list(),.get_items().
To be honest I have tried them but it either print the lication of function on the memory or print one link, but it sound like it should have some information about the download, maybe I haven’t used these correct?

for me even getting tile name/ID from the request can help because then I can use it for the api catalog

Hi,

We are working on a solution. It should be possible using the updateOutputMetadata function in the evalscript, we just needed to update the docs :slight_smile: so hang on and I’ll post the solution once we have tested it.

1 Like

Hi,

the solution to your problem should be solved by the evalscript is below. Using the updateOutputMetadata function, you will return a json file containing a list of the original tile IDs in your AOI and time range, that contain the information on whether the acquisition was S2A or S2B. For example, S2B_OPER_MSI_L2A_TL_SGS__20190228T143058_A010344_T33TVM_N02.11

You will need to create an extra output, if you are also requesting the image at the same time.

//VERSION=3

function setup() {
  return {
    input: ["B02", "B03", "B04"],
    mosaicking: Mosaicking.TILE,
    output: { id:"default", bands: 3}
  }
}

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    var dds = [];
    for (i=0; i<scenes.length; i++){
      dds.push(scenes[i].tileOriginalId)
    }
    outputMetadata.userData = { "original_tile_ids":  JSON.stringify(dds) }
}

function evaluatePixel(samples) {
  return [ 2.5*samples[0].B04, 2.5*samples[0].B03, 2.5*samples[0].B02 ]
}

If you have any other questions, let us know!

1 Like

Thanks Wiliam! I have tried to put it in my evalscript but the result image (response) is still the same array with bands but it doesn’t contain inside the information about the tile, how can I retrieve the outputMetadata ?

this is the evalscript I am using , with the outputMetadata implemented:

#get image with sen1 sen2 
evalscript = """
function setup() {
  return {
    input: [{
        datasource: "LANDS89",
        bands: ["B02","B03","B04","B05","B06","B07" ]
      },
      {
        datasource: "S2L2A",
        bands: ["B02","B03","B04","B8A","B11","B12"]
      }
    ],
    output: [{
      bands: 12,
      sampleType:"FLOAT32"
    }]
  }
}

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    var dds = [];
    for (i=0; i<scenes.length; i++){
      dds.push(scenes[i].tileOriginalId)
    }
    outputMetadata.userData = { "original_tile_ids":  JSON.stringify(dds) }
}

function evaluatePixel(samples) {
  var l8 = samples.LANDS89[0]
  var s2 = samples.S2L2A[0] 
  
  return [s2.B02,s2.B03,s2.B04,s2.B8A,s2.B11,s2.B12,l8.B02,l8.B03,l8.B04,l8.B05,l8.B06,l8.B07]
}
"""

Hi @reutkeller ,

I have a couple of remarks and suggestions, so let’s go through them one-by-one.

function setup

The mosaicking parameter in function setup() must be set to TILE to access the tileOriginalId:

function setup() {
  return {
    input: [{
        datasource: "LANDS89",
        bands: ["B02","B03","B04","B05","B06","B07" ]
      },
      {
        datasource: "S2L2A",
        bands: ["B02","B03","B04","B8A","B11","B12"]
      }
    ],
    output: [{
      bands: 12,
      sampleType:"FLOAT32"
    }],
    mosaicking: Mosaicking.TILE
  }
}

updateOutputMetadata

I see in your function evaluatePixel() that you only return data for the first position of the returned data array:

function evaluatePixel(samples) {
  var l8 = samples.LANDS89[0]
  var s2 = samples.S2L2A[0] 
  ...

Note: With Mosaicking.TILE this will only return data from the first tile in the data array and there won’t be any mosaicking performed.

So if you only need the tile ID for exactly this one acquisition, your function updateOutputMetadata should look like this:

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    outputMetadata.userData = { "original_tile_id":  scenes.S2L2A.scenes[0].tileOriginalId }
}

scenes.S2L2A.scenes[0].tileOriginalId is needed because you first access the scenes object containing scenes for Sentinel-2 and Landsat, then access the datacollection Id (you specified the id as S2L2A), within the data collection you access the first tile of the data array with scenes[0] and then draw out the tileOriginalId.

You can also preselect the S2 scenes and write them to a variable if you prefer that:

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    var scenes_s2 = scenes.S2L2A;
    outputMetadata.userData = { "original_tile_id":  scenes_s2.scenes[0].tileOriginalId }
}

responses

Note that function updateOutputMetadata generates a JSON output file that also needs to be added to the request responses like this:

responses=[
        SentinelHubRequest.output_response('default', MimeType.TIFF),
        SentinelHubRequest.output_response('userdata', MimeType.JSON),
    ],

The response will be a .tar file that contains the default.TIFF and userdata.JSON files.


return list of all tile ids

If you want the whole list of tiles in the specified location and time range, you could push all tileOriginalId to a list and return this in the JSON like this:

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    var scenes_s2 = scenes.S2L2A;
    var dds = [];
    for (i=0; i<scenes_s2.scenes.length; i++){
      dds.push(scenes_s2.scenes[i].tileOriginalId)
    }
    outputMetadata.userData = { "original_tile_ids":  JSON.stringify(dds) }
}
1 Like

Hello Max

thank you for your very detailed answer.
For now, the part that doesn’t work is teh response-

NameError                                 Traceback (most recent call last)
/tmp/ipykernel_3822/2650101103.py in <module>
     38             responses=[
     39                     SentinelHubRequest.output_response('default', MimeType.TIFF),
---> 40                     SentinelHubRequest.output_response('userdata', undefined),
     41                 ],
     42             data_folder='fake/folder/',

NameError: name 'undefined' is not defined

should it be JSON there instead of undefined?

and another question- where can I read about where the images stored? I’m a bit confused about where things stored based on the function that you have used with the scenes and I need tounderstand it better.

You are right, I corrected the response section of my previous post :wink:

1 Like

I am not quite sure what you mean. Can you be more specific and let me know which part you are struggling with?

The function updateOutputMetadata returns the requested metadata in a separate JSON file, whereas function evaluatePixel is there for the image output.

1 Like

Hello,

I’m trying to do something similar- but this time to access only sentinel-2 bands together with the tile.
For reason I cannot find I get error :

Server response: “{“error”:{“status”:400,“reason”:“Bad Request”,“message”:“Output deafult requested but missing from function setup()”,“code”:“COMMON_BAD_PAYLOAD”}}”

This is how I tried to retrieve the image:

#get image with sen1 sen2 
evalscript = """
function setup() {
  return {
    input: [
      {
        datasource: "S2L2A",
        bands: ["B02","B03","B04","B8A","B11","B12"]
      }
    ],
    output: [{
      bands: 7,
      sampleType:"FLOAT32"
    }],
    mosaicking: Mosaicking.TILE
  }
}

function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
    var scenes_s2 = scenes.S2L2A;
    outputMetadata.userData = { "original_tile_id":  scenes_s2.scenes[0].tileOriginalId }
}

function evaluatePixel(samples) {
  var s2 = samples.S2L2A[0] 
  return [s2.B02,s2.B03,s2.B04,s2.B8A,s2.B11,s2.B12]
}
"""

Function to get image :

def get_sen2(evalscript,geom,d,bbox,bbox_size):
    request=SentinelHubRequest(
        evalscript=evalscript,
        geometry=geom,
        input_data=[
            SentinelHubRequest.input_data(
                data_collection=DataCollection.SENTINEL2_L2A,
                time_interval=(d,d),
                other_args={"id":"S2L2A"}
            ),
        ],
        
        responses=[
            SentinelHubRequest.output_response('deafult',MimeType.TIFF),
            SentinelHubRequest.output_response('userdata',MimeType.JSON),
            
        ],
        
        data_folder='fake/folder',
        bbox=bbox,
        size=bbox_size,
        config=config
        
    )
        
    response = request.get_data(save_data=False)
    
    return response

I understand that the error relates to the setup function but I don’t understand what is missing :frowning: . I saw another post with siimlar error thathad didn’t have the response part, but I do have it, so I’m not sure why it doesn’t work. please help me find the issue here! Thanks :slight_smile:

The error (hard to catch if you are not paying proper attention despite the error message being clear) is the fact that in SentinelHubRequest you are requesting a response named deafult (and not default).

So all in all, your error is related to the discrepancy between what you are requesting (SentinelHubRequest) and what you are outputting (evalscript).

A side note - you are setting the id of the collection, but that is really not needed when you are not doing data fusion, so it only makes your evalscript and request harder to debug.

Disclaimer: I haven’t tested your request

1 Like