Attach pixel geocoding in graph builder

It’s always looking for a file:

Error: [NodeId: Read] The ‘file’ parameter is not set

It seems that it is not possible to read a product, apply the pixel geocoding and use it in graph directly. I have also tried to save this product directly with:

ProductIO.writeProduct(p_preprocessed,“NetCDF4-CF”,“p_preprocessed.nc”, None)

But still no success.

Can you post your graph?

Here it is:

Export_netcdf4.xml (1.3 KB)

The xml look good.
Strange that you get the error

Error: [NodeId: Read] The ‘file’ parameter is not set

You set the variable Input in the command.
So If there is an error I would have expected something like

File not found: "p_preprocessed"

or

File not found: "${Input}"

But that it says “not set” means that the variable p_preprocessed is probably empty

The variable was empty. But even trying with the original product I get the same error message.

Hi @marpet.

I’m trying to apply RayleighCorrection to Sentinel-3 OLCI data. I also need to apply pixel-geocoding and I’ve tried your code. However, I’m getting an error:

    pixelGeoCoding = GeoCodingFactory.createPixelGeoCoding(latBand, lonBand, validMask="", searchRadius=3)
RuntimeError: no matching Java method overloads found

this is the full code:

import snappy

def main():
    sourceProduct = snappy.ProductIO.readProduct("S3A_OL_1_EFR____20200319T094652_20200319T094952_20200320T135124_0179_056_136_2160_LN1_O_NT_002.SEN3/xfdumanifest.xml")
    print(list(sourceProduct.getBandNames()))

    latBand = sourceProduct.getBand('latitude')
    lonBand = sourceProduct.getBand('longitude')
    GeoCodingFactory= snappy.jpy.get_type('org.esa.snap.core.datamodel.GeoCodingFactory')
    # validmask can be set to None if all lat/lon values are valid in the bands
    # searchRadius defines the radius in pixels when searching for the best pixel for a geo-location. A value between 3and 5 is probably good. Depends also on the resolution.
    pixelGeoCoding = GeoCodingFactory.createPixelGeoCoding(latBand, lonBand, validMask=" ", searchRadius=3)
    sourceProduct.setSceneGeoCoding(pixelGeoCoding)
    
    HashMap = snappy.jpy.get_type('java.util.HashMap')    
    snappy.GPF.getDefaultInstance().getOperatorSpiRegistry().loadOperatorSpis()

    parameters = HashMap()
    parameters.put('sourceBandNames', ['Oa01_radiance','Oa17_radiance','Oa21_radiance','quality_flags'])
    parameters.put('computeTaur', False)
    parameters.put('computeRBrr', True)
    parameters.put('computeRtoaNg', False)
    parameters.put('computeRtoa', False)
    parameters.put('addAirMass', False)
    parameters.put('s2MsiTargetResolution', 20)
    parameters.put('s2MsiSeaLevelPressure', 1013.25)
    parameters.put('s2MsiOzone', 300.0)
    
    result1 = snappy.GPF.createProduct('RayleighCorrection', parameters, sourceProduct)

    snappy.ProductIO.writeProduct(result1, "snappy_sample.dim", 'BEAM-DIMAP')
    
if __name__=='__main__':
    main()

Python version is 3.6.10 and snap has been updated to the latest version available.

HI @clausmichele

I’m not sure why the method is not found. The call looks correct.
However, the GeoCodingFactory is actually deprecated and ComponentGeoCoding should be used.
But to set this properly up is more complex.
It is easier to simply set a system property and the pixel-based GeoCoding will be used of the data by default.
This can be set using SNAP Desktop:
image
Or you add this property in the USER_HOME/snap/etc folder to the s3tbx.properties file.
This is one example: s3tbx.properties (431 Bytes)
The first entry is the required property. It enables the pixel-based GeoCoding.

Thanks for the hint! The setting was indeed applied in the GUI, but it wasn’t in the property file.
Anyway, now I get the following error. How do I specify a list of bands? A Python list does not work, I guess I need to istantiate a Java list but I do not know how.

parameters.put('sourceBandNames', ['Oa01_radiance','Oa17_radiance','Oa21_radiance','quality_flags'])
ValueError: cannot convert a Python 'list' to a Java 'java.lang.Object'

What I’ve tried:

StringArray1D = snappy.jpy.get_type('[Ljava.lang.String;')
bandsList = StringArray1D(['a','b'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: no constructor found (missing JType attribute '__jinit__')
String = snappy.jpy.get_type('java.lang.String')
StringArray1D = snappy.jpy.get_type('[Ljava.lang.String;')
bandsList = StringArray1D([String('a'),String('b')])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: no constructor found (missing JType attribute '__jinit__')

so if it’s not possible to create a new Java array of strings, it would be enough to remove unnecessary bands from the list obtained using the following approach, but how?

sourceProduct.getBandNames()

The easiest way here is to prove simple String:
parameters.put('sourceBandNames', 'Oa01_radiance,Oa17_radiance,Oa21_radiance,quality_flags')

This can be parsed and properly converted by Java.
It would also be possible to create a Band array and fill it with bands from the product.

bands = jpy.array('org.esa.snap.Band', 4)
bands[0] = peoduct.getBand('Oa01_radiance')
...
parameters.put('sourceBandNames', bands)

But the first option is more convenient.

1 Like

Thanks a lot, it works!

1 Like