Slicing OLCI L2 RR water products

Hi
OLCI L2 WRR products are (typically) served as half-orbits, i.e. 44 minutes long, files, while WFR products are served as (typically) 3 minutes long files. The “Sentinel 3 PDGS File Naming Convention”, clearly defines the data start timestamp and data stop timestamp in the filename.

Is it possible to break a WRR product in two (or more) products by time?
E.g. I have
S3A_OL_2_WRR____20180912T085904_20180912T094316_…
product;
is it possible to break it in two files, each 22’ long, like
S3A_OL_2_WRR____20180912T085904_20180912T092110_…
S3A_OL_2_WRR____20180912T092111_20180912T094316_…

Or to extract just a 6 minutes window, e.g.:
S3A_OL_2_WRR____20180912T091204_20180912T091804_…
?

If there were a snappy function to do this … it would be magnificent!

Thanks for any information

 Mario

Hi Mario,

there is no functionality which supports this directly. But with a bit of coding it should be possibly with snappy.
There is the Subset operator which can be use to tailor a product by pixel coordinates or by geo-location.
As sensing 6 minutes have always the same number of lines you could define the subsets hard coded.
But there is also the option to get for each line (or pixel) the sensing time. So you could iterate over the lines and after reaching 6 minutes, or whatever threshold you use, you can note the line number and split the product.
You can get the time by calling on the product:

tc = product.getTimeCoding()
mjd = tc.getMJD() # returns the MJD2000 as double value

The mjd value can probably passed to some Python function, so that you can work with it easily. But I’m not a Python expert so I can’t tell you more.

I hope this helps you to get started.

Thanks a lot.
It looks like a good starting point.
I’ll let you know how it proceeds :slight_smile:
BTW, would this work also with L1 products?
Thanks again
Mario

Yes, it works with most products, as long there is time information attached. The behaviour might be different, some provide for each pixel different time information, other the same time for each line or the whole scene. This depends on the sensor, the data contained in the product and also on the implementation of the reader.

I have forgotten something in the sample code. The coordinate to retrieve the time for must be given as parameter:

from snappy import PixelPos

tc = product.getTimeCoding()
mjd = tc.getMJD(PixelPos(xPos, yPos)) # returns the MJD2000 as double value at this pixel position 

This is the link to the API Doc: http://step.esa.int/docs/v6.0/apidoc/engine/org/esa/snap/core/datamodel/TimeCoding.html

Hi Marco
sorry to come back to you after more than a month, but I had to switch to another project. Anyway, yesterday I resumed this activity and I tried what you were recommending. I found that there is no getTimeCoding attribute or method in the product object:

In [3]: p=snappy.ProductIO.readProduct("xyz.SEN3")
In [4]: tc=p.getTimeCoding()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-37-e282a706858f> in <module>()
----> 1 tc=p.getTimeCoding()

AttributeError: 'org.esa.snap.core.datamodel.Product' object has no attribute 'getTimeCoding'

Actually there is the getSceneTimeCoding() method but it doesn’t return anything:

In [38]: tc=p.getSceneTimeCoding()

In [39]: type(tc)
Out[39]: NoneType

In the other hand the getSceneGeoCoding() looks like working as described in the API documentation site.

Anyway, what about if I get

ts1=p.getStartTime()
ts2=p.getEndTime()

then I associate ts1 to the first row of the swath and ts2 to the last row, and assume that every line in between would have a timestamp linear between the two? i.e. for line n

ts=ts1 + (ts2 - ts1)*n/h

where

h=p.getSceneRasterHeight()

Thanks
Mario

PS: I’m using snappy 6.0.9, if that matters.

Ah, sorry for this confusion. I replied without double checking the code.
Yes, the method is getSceneTimeCoding() and I thought a default TimeCoding would be created on the basis of the start and end time. As it turns out, it is not.

You can use the start and end time as you suggested. This is actually the default behavior I had in mind.
When you retrieve the start and end time you better do:

ts1=p.getStartTime().getAsDate().getTime()
ts2=p.getEndTime().getAsDate().getTime()

This will give you the milliseconds since January 1, 1970.
The results of getStartTime() and getEndTime() can’t be used directly in the calculation, because they are Java objects.

If you like, you could do

LineTC = jpy.get_type('org.esa.snap.core.datamodel.LineTimeCoding')
time_coding = LineTC(h, ts1.getMJD(), ts2.getMJD())
# and later
mjd = time_coding.getMJD(PixelPos(xPos, yPos))

But your suggestion is simpler.

Hallo
I finally wrote a small code that trims an OLCI product to a rectangular box.
Basically I maintain only the rows that intersect, or lie within, the box; i.e. that have at least a pixel in the box.
I apply this to all the netcdf files of the product, creating the trimmed file in a new directory.
Apparently this works for L1,L2,FR and RR products.
At the end I didn’t use snappy at all, I just used the python netcdf4 module.
But … what about the xfdumanifest.xml file?
I discovered the https://public.ccsds.org/Pubs/661x0b1.pdf standard that rules this file … but … but … is there an easy way to generate this file, starting from the trimmed netcdf files?
Just copying the original one in the new directory apparently works.
SNAP is able to open the new product and correctly refers it on the map. BUT, when you open the metadata, it reads those from the xfdumanifest.xml file.

Thanks

Mario