jiayuasu opened a new issue, #3213:
URL: https://github.com/apache/sedona/issues/3213

   ## Describe the bug
   
   A raster returned from a Python UDF cannot carry a NODATA value that differs 
from its input, and Python and the JVM report different NODATA for the same 
band.
   
   `GridSampleDimensionSerializer.write()` writes a nodata double "for 
interoperability with Python RasterType", but `read()` discards it and rebuilds 
the sample dimension from the Kryo `Category[]` blob instead:
   
   ```java
   double offset = input.readDouble();
   double scale = input.readDouble();
   input.readDouble(); // noDataValue is included in categories, so we just 
skip it
   input.readInt();
   Category[] categories = kryo.readObject(input, Category[].class);
   return new GridSampleDimension(description, categories, offset, scale);
   ```
   
   `InDbSedonaRaster.with_bands()` replays those blobs from the source raster, 
so the value Python declares in `bands_meta` never reaches the JVM. Two 
consequences:
   
   **1. Inherited NODATA silently corrupts derived rasters.** Narrowing keeps 
`_category_blobs[:n_bands]`, so a mask carved out of a scene inherits band 1's 
NODATA. Given a 4-band raster with NODATA `0` on band 1 and a UDF thresholding 
it to a 0/1 mask, every `0` in the mask is treated as NODATA:
   
   ```python
   @udf(returnType=RasterType())
   def mask(raster):
       return raster.with_bands((raster.as_numpy()[0] < 6).astype(np.float64))
   
   # on a 12-pixel raster:
   #   RS_Count(out, 1, true)  -> 6    (zeros skipped as NODATA)
   #   RS_Count(out, 1, false) -> 12
   #   RS_BandNoDataValue(out, 1) -> 0.0
   ```
   
   There is no way to correct this from inside the UDF; `RS_SetBandNoDataValue` 
afterwards is the only workaround.
   
   **2. Python and the JVM disagree.** Widening replicates the last source 
band's category blob while `bands_meta` records `NaN`. Widening a 4-band raster 
whose band 4 has NODATA `-1` to 8 bands:
   
   ```
   python  raster.bands_meta -> [nan, nan, nan, -1.0, nan, nan, nan, nan]
   sql     RS_BandNoDataValue(out, 5..8) -> -1.0
   ```
   
   ## Expected behavior
   
   The nodata double on the wire should be authoritative, and `with_bands()` 
should accept an explicit NODATA — parity with `RS_MapAlgebra`'s `noDataValue` 
argument.
   
   ## Proposed fix
   
   Have `read()` reconcile the two via the existing 
`RasterUtils.createSampleDimensionWithNoDataValue()`, which early-returns when 
the values already agree. The JVM writer emits 
`RasterUtils.getNoDataValue(sampleDimension)` — derived from the categories — 
so JVM-to-JVM round trips reconcile to a no-op and are unaffected. This mirrors 
the `reconcileColorModel()` that #2956 added for the colour model, for the same 
class of Python-mutated-raster mismatch.
   
   Then add `with_bands(new_data, nodata=...)` on the Python side, and make 
widened bands report the value they will actually receive rather than `NaN`.
   
   ## Sedona version
   
   master (`1.9.1-SNAPSHOT`). Introduced with the Python raster serializer in 
#2956, so not present in any release yet.
   
   ## Environment
   
   Reproduced with Spark 3.4 / Scala 2.12, `-Dgeotools`, pyspark 3.4.4.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to