Repository navigation
Decimate inputDataExceptionMask when bandpassing mixed-mode RSLCs - #409
Conversation
| mask_path = f"{freq_path}/inputDataExceptionMask" | ||
| if mask_path not in src_h5: | ||
| return | ||
|
|
There was a problem hiding this comment.
you may want to add a sanity check to ensure decimation_factor >= 1, and I assume if decimation_factor == 1 you would return without doing anything.
There was a problem hiding this comment.
Yes, similar to @gshiroma's suggestion that we add the code below to handle the case that decimation_factor is equal to 0
# Handle the case when the decimation_factor == 0
decimation_factor = max(decimation_factor, 1)
| decimation_factor = int(np.round( | ||
| bandpass_meta['range_spacing'] / | ||
| target_meta_data.rg_pxl_spacing)) |
There was a problem hiding this comment.
| decimation_factor = int(np.round( | |
| bandpass_meta['range_spacing'] / | |
| target_meta_data.rg_pxl_spacing)) | |
| decimation_factor = max(int(np.round( | |
| bandpass_meta['range_spacing'] / | |
| target_meta_data.rg_pxl_spacing)), 1) |
To handle the case when decimation_factor = 0.
|
|
||
| src_mask = src_h5[mask_path] | ||
| lines, samples = src_mask.shape | ||
| if samples == bandpassed_samples: |
There was a problem hiding this comment.
| if samples == bandpassed_samples: | |
| if samples == bandpassed_samples: | |
| if decimation_factor != 1: | |
| raise ValueError("mismatch between decimation factor and image size") | |
| # else earlier code has already copied mask, so nothing to do. |
Should have a sanity check here in the no-op case.
|
|
||
| attrs = dict(src_mask.attrs) | ||
| del dst_h5[mask_path] | ||
| dst_mask = dst_h5.create_dataset( |
There was a problem hiding this comment.
I wonder if we need to specify the HDF5 missing data value here as well (not the _FillValue attribute). I'll have to look up how to do this using h5py.
There was a problem hiding this comment.
The create_dataset method has the fillvalue keyword (h5py API) to specify the HDF5-level fill value for uninitialized data (C or C++ API). I don't think we're actually doing this explicitly anywhere in ISCE3 yet, but recent benchmarking shows it could be important. In this case, the optimal thing to do would be to
- Set
fillvalueat dataset creation time. - Write the entire dataset in one sequential pass over chunks (without writing anything else to the HDF5 file).
- This stores the mask in as few pages as possible.
- Skip writing any chunks where all pixels are equal to
fillvalue.- Minimizes the amount of chunk metadata stored to disk.
- Allows HDF5 to trivially memset the chunk on read instead of decompressing, which is around 30x faster.
I don't think this necessarily has to be implemented for this PR, but I expect we may expend some effort implementing this strategy for many products/datasets in the future.
There was a problem hiding this comment.
Thanks @bhawkins for this. It might be better that we open an issue for this since once this PR is merged, we might forget this.
| # Equals the resample_width_end that bandpass_shift_spectrum trims the | ||
| # SLC to, so the mask drops the same trailing samples as the rasters | ||
| samples_used = bandpassed_samples * decimation_factor | ||
| if samples_used > samples: |
There was a problem hiding this comment.
Typically decimation might end up with the case samples_used up to samples + decimation_factor - 1, and this is a stronger assumption. Seems okay with me since it's in the docstring.
Mixed-mode (20/40 MHz) InSAR crashed in
prepare_insar_hdf5with:bandpass_insarcopies the RSLC tree verbatim withcp_h5_meta_data, thenrewrites the polarization rasters,
validSamplesSubSwath*andslantRangeonto the decimated range grid — but never
inputDataExceptionMask. The maskwas left on the pre-bandpass grid at twice the width of the swath it
describes. The shape check in
_RSLCInputDataExceptionMasksurfaced a realinconsistency, not a spurious assertion.
Two fixes:
1. Decimate the mask onto the bandpassed grid. New
decimate_input_data_exception_maskmaps input sampleito output samplei // decimation_factor— the same mappingvalidSamplesSubSwath{i}isrescaled by — and OR-reduces every bit of each group, so no set bit is lost.
That is the aggregation the dataset is defined by ("bitwise OR of input data
exception codes ... also includes OR of validity mask bits") and applies
unchanged to the 8-bit mask (anomaly codes only) and the 16-bit mask (plus
per-polarization validity bits in the high byte). The output width is read
from the bandpassed SLC rather than recomputed, so it cannot disagree with
the rasters; dtype, chunking, compression and attributes are preserved, and
the trailing samples dropped are exactly those
bandpass_shift_spectrumtrims from the SLC (verified
bandpassed_samples * factor == resample_width_endover factors 2–8 × widths 1–200 plus the real widths).2. Fix a pre-existing off-by-one in the
validSamplesSubSwathrescaling.bandpass_ratiois0.499999999996329, not0.5, because its numerator anddenominator are accumulated separately (
3.1228381041437387vs6.245676208333333).int(i * ratio)therefore loses a pixel on everyeven index — the exact
i/2is a whole number that any downward errordrops below, while odd indices land on
x.5and survive. On the test datathe sub-swath start went
1602 → 800instead of801, claiming twoout-of-swath samples as valid. Both paths now share one integer
decimation_factorand the identicali // decimation_factormapping.Test plan
test_decimate_input_data_exception_mask: covers uint8/uint16,bit preservation across the full dtype width, width taken from the SLC,
the already-on-grid no-op, and the too-narrow-mask
ValueErrorpytest tests/python/packages/nisar/workflows/bandpass_insar.py— 3 passedtest_bandpass_runindependently reproduces the off-by-one on committeddata (
[200,200] → [99,99]before,[100,100]after) with a differentratio error, so it is not specific to one product
nisar.workflows.insaron a real 20/40 MHz QPDH/DHDH pair:prepare_insar_hdf5completes (115 s, previously crashed); bandpassedHH,inputDataExceptionMaskandslantRangeall agree at(54720, 26291); decimation is a bit-exact OR-reduction of the source