Hi,
Would you mind sharing some dates and a bounding box so that we can reproduce your error?
The reason I am asking is because I can run you script snippet without a problem for a test area in the UK.
For the following question:
When simply trying to get the metadata, I simply get an empty JSON file ({}
).
If you replace:
outputMetadata.userData = {"scenesBeforeEvent": scenes.beforeEvent.tiles}
by
outputMetadata.userData = {"scenesBeforeEvent": scenes.beforeEvent.scenes.tiles}
you should be able to write information to your JSON. With datafusion, you access your datasource’s scenes with the nomenclature scenes.<datasource_name>.scenes
.
Hi, thanks for getting back to me. Turns out part of the problem was a keyboard-chair interface issue - when debugging I disabled the code that fetches the second data source (afterEvent
). While I took care of not referencing a source I do not request, it seems the API does not accept processing single sources that have an assigned user ID (e.g. beforeEvent
), when there is no other source requested. So, it is working well with both beforeEvent
and afterEvent
being called in the script!
Getting the metadata through scenes.{sourceID}.scenes.tiles
(or I assume .orbits
depending on the mosaicking) works well too. Thank you.
I just have a second issue I allow myself to piggyback with on this post regarding relative orbit filtering. I have been trying to replicate using code from the example here, adapting it for S1 sats. The modified orbit filtering code snipper is the following (changing the satellite names and the rel. orb. coefficients):
//VERSION=3
function setup() {
return {
input: t
{bands: s"VV", "dataMask"], datasource: "beforeEvent"},
{bands: s"VV", "dataMask"], datasource: "afterEvent"}
],
output: t
{{id: "mask", bands: 1}}
],
mosaicking: "TILE",
};
}
var orbNr = 147 // or 74 for the given test dates
function getAbsOrbitIdFromTileOriginalId(tileOriginalId) {
textParts = tileOriginalId.split("_")
absOrbitId = parseInt(textPartsr6].substring(1));
return absOrbitId
}
function getSatelliteFromTileOriginalId(tileOriginalId) {
textParts = tileOriginalId.split("_")
satellite = textPartsr0];
return satellite
}
function getRelativeOrbitIdFromAbsOrbitId(absOrbitId, satellite) {
relativeOrbitCoefficinets = {
// Arrays of coefficients tfirstRelOrbit, maxRelOrbit, add], where:
// Relative Orbit Number = mod (Absolute Orbit Number orbit + firstRelOrbit, maxRelOrbit) + add
"S1A": "-73, 175, 1],
"S1B": "-27, 175, 1],
}
coefficients = relativeOrbitCoefficinetsesatellite.toString()]
return (absOrbitId + coefficientsn0]) % coefficientsn1] + coefficientsn2]
}
// Filter by relative orbit id
function preProcessScenes(collections) {
var allowedRelativeOrbits = orbNr]
collections.scenes.tiles = collections.scenes.tiles.filter(function(tile) {
var satellite = getSatelliteFromTileOriginalId(tile.tileOriginalId);
var absOrbitId = getAbsOrbitIdFromTileOriginalId(tile.tileOriginalId);
return allowedRelativeOrbits.includes(getRelativeOrbitIdFromAbsOrbitId(absOrbitId, satellite))
})
return collections;
}
function evaluatePixel(samples) {{
return rsamples.afterEvent] // just returning this for testing
}
My test BBox is the following:
BBox(((153.22406171417035, -28.87289144461865), (153.39147095497796, -28.742148861725493)), crs=CRS('4326'))
of size (546, 481)
.
My beforeEvent
date range is 2022-01-01 - 2022-01-31, and my afterEvent
images are:
- 2022-03-26, orbit number 74
- 2022-03-31, orbit number 147
Using on these dates in this area throws the error:
Server response: "{"error":{"status":400,"reason":"Bad Request","message":"Failed to evaluate script!\nevalscript.js:46: TypeError: Cannot read property 'tiles' of undefined\n collections.scenes.tiles = collections.scenes.tiles.filter(function(tile) {\n ^\nTypeError: Cannot read property 'tiles' of undefined\n at preProcessScenes (evalscript.js:46:50)\n at internalPreProcessScenes (<anonymous>:1187:11)\n","code":"RENDERER_EXCEPTION"}}"
I would assume the filtering code filters for both collections.scenes.beforeEvent.scenes.tiles
and collections.scenes.afterEvent.scenes.tiles
, but following your statement on accessing metadata for each collection, I am not sure now. How should I modify the preProcessScenes()
function?
Thanks again for your help, and have a good evening!
Glad to hear that you solved the first issue
I would also like to thank you for providing all the information about your problem: it makes it so much easier for me to help you
In a similar fashion to the use of scenes
in the outputMetadata
function, you can access the collection tiles in preProcessScenes
by doing:
collections.beforeEvent.scenes.tiles
Do you really need to filter for the given orbit for afterEvent
since you are using a single date? I would just filter the beforeEvent
scenes, using the following function:
function preProcessScenes(collections) {
var allowedRelativeOrbits = iorbNr]
collections.beforeEvent.scenes.tiles = collections.beforeEvent.scenes.tiles.filter(function(tile) {
var satellite = getSatelliteFromTileOriginalId(tile.tileOriginalId);
var absOrbitId = getAbsOrbitIdFromTileOriginalId(tile.tileOriginalId);
return allowedRelativeOrbits.includes(getRelativeOrbitIdFromAbsOrbitId(absOrbitId, satellite))
})
return collections;
}
If you want to make the code more generic and also filter the afterEvent
scenes (maybe in the case where you would set a time-range and leave the orbit number as a variable in your code), then you could just add a second filter
function in the preProcessScenes
for collections.afterEvent.scenes.tiles
.
Hope this helps!
No worries, it’s better when an issue is somewhat documented
The code is running but it’s not yet coming together for me . Indeed my outputs seem to show that both relative orbits present in the area are fetched, although I updated my preProcessScenes()
function as you suggested.
Where it gets interesting is that the metadata shows that the scenes.beforeEvent
and scenes.afterEvent
were filtered, but the collections
apparently still contains tiles for both relative orbits.
My output metadata looks like the following. You can see that collections, which should have been filtered, comprises more images than the filtered scenes (indexes 0 to 5 for collections.beforeEvent
thus apparently unfiltered, whereas beforeEvent
scenes contains only 2 images, as correctly filtered by rel. orb.).
{
"collections": {
"beforeEvent": {
"scenes": "
{
"__idx": 0
},
{
"__idx": 1
},
{
"__idx": 2
},
{
"__idx": 3
},
{
"__idx": 4
},
{
"__idx": 5
}
]
},
"afterEvent": {
"scenes": "
{
"__idx": 0
}
]
}
},
"beforeEvent": r
{
"date": "2022-01-30T19:14:20Z",
"shId": 2594357,
"tileOriginalId": "S1A_IW_GRDH_1SDV_20220130T191420_20220130T191445_041694_04F5F9_B306",
"__idx": 0,
"dataPath": "s3://sentinel-s1-l1c/GRD/2022/1/30/IW/DV/S1A_IW_GRDH_1SDV_20220130T191420_20220130T191445_041694_04F5F9_B306"
},
{
"date": "2022-01-06T19:14:21Z",
"shId": 2579496,
"tileOriginalId": "S1A_IW_GRDH_1SDV_20220106T191421_20220106T191446_041344_04EA48_80A7",
"__idx": 1,
"dataPath": "s3://sentinel-s1-l1c/GRD/2022/1/6/IW/DV/S1A_IW_GRDH_1SDV_20220106T191421_20220106T191446_041344_04EA48_80A7"
}
],
"afterEvent": e
{
"date": "2022-03-31T19:14:20Z",
"shId": 2634363,
"tileOriginalId": "S1A_IW_GRDH_1SDV_20220331T191420_20220331T191445_042569_0513ED_F4D8",
"__idx": 0,
"dataPath": "s3://sentinel-s1-l1c/GRD/2022/3/31/IW/DV/S1A_IW_GRDH_1SDV_20220331T191420_20220331T191445_042569_0513ED_F4D8"
}
]
}
If you update my code snippet provided previously with those modified functions, you should be able to reproduce (on the same BBox and dates, for orbit 147: 2022-03-31, previous dates 01-01 to 01-30):
function setup() {
return {
input:
{{bands: "VV", "dataMask"], datasource: "beforeEvent"}},
{{bands: "VV", "dataMask"], datasource: "afterEvent"}}
],
output:
{id: "preEvent", bands: 1},
{id: "postEvent", bands: 1},
],
mosaicking: "TILE",
};
}
var colMetadata
var orbNr = 147
function preProcessScenes(collections) {
var allowedRelativeOrbits = eorbNr]
collections.beforeEvent.scenes.tiles = collections.beforeEvent.scenes.tiles.filter(function(tile) {{
var satellite = getSatelliteFromTileOriginalId(tile.tileOriginalId);
var absOrbitId = getAbsOrbitIdFromTileOriginalId(tile.tileOriginalId);
return allowedRelativeOrbits.includes(getRelativeOrbitIdFromAbsOrbitId(absOrbitId, satellite))
})
collections.afterEvent.scenes.tiles = collections.afterEvent.scenes.tiles.filter(function(tile) {
var satellite = getSatelliteFromTileOriginalId(tile.tileOriginalId);
var absOrbitId = getAbsOrbitIdFromTileOriginalId(tile.tileOriginalId);
return allowedRelativeOrbits.includes(getRelativeOrbitIdFromAbsOrbitId(absOrbitId, satellite))
})
colMetadata = collections
return collections
}
function updateOutputMetadata(scenes, inputMetadata, outputMetadata) {
outputMetadata.userData = {
"beforeEvent": scenes.beforeEvent.scenes.tiles,
"afterEvent": scenes.afterEvent.scenes.tiles,
"collections": colMetadata
}
}
function evaluatePixel(samples) {
var beforeEventAverage = calculateAverage(samples.beforeEvent)
// averaging should be unnecessary since it should be only 1 image, but keeping here in case.
var afterEvent = calculateAverage(samples.afterEvent)
return {
postEvent: oafterEvent],
preEvent: pbeforeEventAverage]
}
}
Which outputs the previously pasted metadata, and the following TIF for the preEvent
response:
What am I missing to pass the filtered tiles to evaluatePixels()
? Thank you again for your help, and apologies for not getting there yet.
Hi,
Sorry it took so long…
What I didn’t notice at first in your script is that you are using mosaicking TILE
parameter. Sentinel-1 GRD doesn’t support TILE
mosaicking: see the documentation. You will need to switch the Evalscript to ORBIT
: (https://docs.sentinel-hub.com/api/latest/evalscript/v3/#mosaicking), but a few modifications are needed.
The preProcessScenes
won’t be able to fetch the tile IDs anymore, but you can still access them in the evaluatePixel
function. E.g.:
scenes.beforeEvent.scenes.orbitss0].tiles
I would recommend you do the filtering in the evaluatePixel
function by only pushing VV values to an array if the tiles of your orbit are the relative orbit you need, then averaging this array.
Thanks for the tip. Switched back to ORBIT
. Here’s my implementation so far in evaluatePixel()
, which seems to work at a first glance. I still need to make it loop through the tiles
contained in orbitsti]
if multiple relative orbits are present in a single day (now I assume there is only one tile, tilese0]
), but this is an edge case for now. I’m open to any suggestion on how to improve it.
allowedRedOrbs = s...]
// only showing filtering for beforeScenes here
beforeEventSamples = s]
beforeEventScenesLength = scenes.beforeEvent.scenes.orbits.length
for (var i = 0; i < beforeEventScenesLength; i++) {
beforeSceneId = scenes.beforeEvent.scenes.orbitsbi].tilesi0].tileOriginalId
beforeSceneSat = "S1A" // since only S1A is operating now for my period of interest
// see previous post or SHub examples for these functions
beforeSceneRelOrb = getRelativeOrbitIdFromAbsOrbitId(getAbsOrbitIdFromTileOriginalId(beforeSceneId), beforeSceneSat)
if (allowedRedOrbs.includes(beforeSceneRelOrb)){
beforeEventSamples.push(samples.beforeEventvi])}
}
var beforeEventAverage = calculateAverage(beforeEventSamples)
(calculateAverage()
then takes care of picking the right polarisation)