Open-EO / openeo-geotrellis-extensions

Java/Scala extensions for Geotrellis, for use with OpenEO GeoPySpark backend.
Apache License 2.0
5 stars 3 forks source link

GDAL exception for some file-cgls netCDFs #123

Open JeroenVerstraelen opened 1 year ago

JeroenVerstraelen commented 1 year ago

When merging the old CglsPyramidFactory into file.PyramidFactory (previously Sentinel2PyramidFactory) I noticed an error when testing pyramid_seq (CglsPyramidFactoryTest#pyramid_seqExtent).

The actual crs of NETCDF:/data/MTDA/BIOPAR/BioPar_FAPAR_V2_Global/2020/20200110/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1.nc:FAPAR is 4326. But pyramid_seq uses a ZoomedLayoutScheme with WebMercator as CRS, which causes GDALWarpOptions.targetCRS=WebMercator in the FileLayerProvider. When rastersource.cellType is called, it results in this error:

java.io.IOException: Exception while determining data type of collection  and item NETCDF:/data/MTDA/BIOPAR/BioPar_FAPAR_V2_Global/2020/20200110/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1.nc:FAPAR. Detailed message: Unable to determine NoData value. GDAL Exception Code: 4

You can test this issue using:

  @Test
  def FileCglsErrorTest(): Unit = {
    val path = "NETCDF:/data/MTDA/BIOPAR/BioPar_FAPAR_V2_Global/2020/20200110/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1/c_gls_FAPAR-RT6_202001100000_GLOBE_PROBAV_V2.0.1.nc:FAPAR"
    val dataPath = GDALPath(path)
    val optionsWorks = GDALWarpOptions(cellSize=Some(CellSize(0.002332672982335701,0.002332672982335701)), alignTargetPixels = false, targetCRS=Some(CRS.fromEpsgCode(4326)), resampleMethod = Some(geotrellis.raster.resample.NearestNeighbor), te=None)
    //val optionsFails = GDALWarpOptions(cellSize=Some(CellSize(0.002332672982335701,0.002332672982335701)), alignTargetPixels = false, targetCRS=Some(WebMercator), resampleMethod = Some(geotrellis.raster.resample.NearestNeighbor), te=None)
    val targetCellType = None
    val source = GDALRasterSource(dataPath, optionsWorks, targetCellType)
    println(source.cellType)
  }
jdries commented 1 year ago

The cellsize could be the issue: it is in degrees, while you'll need one in meters to work with webmercator.

JeroenVerstraelen commented 1 year ago

The issue does appear to be because of PyramidFactory.maxSpatialResolution, currently the code uses the max spatial resolution specified in layercatalog.json:

    val faparPyramidFactory = new PyramidFactory(
      openSearchClient, "", netcdfVariables, "",
      maxSpatialResolution = CellSize(0.008928571428584,0.008928571428569)
    )

Which then causes FileLayerProvider.maxZoom to be wrong:

  val maxZoom: Int = layoutScheme match {
    case z: ZoomedLayoutScheme => z.zoom(0, 0, maxSpatialResolution)
    case _ => 14
  }

Here it uses ZoomedLayoutScheme(WebMercator).zoom(0, 0, CellSize(0.008928571428584,0.008928571428569)) = 26. So it is calculating a zoom level in WebMercator using a CellSize in EPSG:4326 which creates a zoom level that is too high for the native resolution of the layer.

The solution would be to edit the maxZoom calculation to take into account the CRS of maxSpatialResolution (= native CRS of the layer) and convert that resolution to WebMercator first.