Fix NaN geolocation crash in swath matchup (DSCOVR EPIC / HE5 fill values) - #119
Merged
Conversation
Co-authored-by: eeholmes <2545978+eeholmes@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] [ISSUE-123] Fix matchup logic for NaN latitude/longitude
Fix NaN geolocation crash in swath matchup (DSCOVR EPIC / HE5 fill values)
Mar 16, 2026
Member
|
@copilot what are the speed costs of this fix? Should I restrict to cases where there are nan's only |
Contributor
Author
The fix already restricts the expensive work to NaN cases only. Here's the breakdown on a 2048×2048 swath (4M pixels):
The key lines in if np.all(np.isfinite(lat_vals)) and np.all(np.isfinite(lon_vals)):
return ds # Fast path — nothing to do.No stacking, no indexing, no copy — just the |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Swath products like DSCOVR EPIC store a large fill value (~−1.27e30) for pixels outside the valid Earth disk. xarray converts these to NaN on read, and scipy's/xoak's KD-tree raises
ValueErrorwhen NaN values appear in the coordinate arrays passed toset_xindex().Changes
_drop_nan_geoloc()helper — new function that stacks all spatial dimensions, drops pixels where lat or lon is NaN/Inf, and returns a 1-D filtered dataset safe forset_xindex(). Fast-path when all coordinates are finite.set_xindex()in_extract_xoak(),_extract_xoak_batch(), and_extract_ndpoint_batch().TestXoakSpatialMethodandTestNdpointSpatialMethod: swath with NaN lat/lon in the last row (mimicking EPIC fill pixels), querying an exact valid pixel, asserting the returned value matches the expected SST (not NaN, no exception).Original prompt
This section details on the original issue you should resolve
<issue_title>For some swath data, Latitude/Longitude is nan outside of swath</issue_title>
<issue_description>Task: Matchups should not fail if Latitude/Longitude have nan
Background. I am debugging a matchup algorithm for DSCOVR EPIC swath data. The HE5 file uses fill values of about -1.2676506e30 outside the valid Earth disk. These should be treated as missing, but the matchup code appears to pass them through and later produces NaNs. Here is a summary of the file structure and a small extracted subset. Please inspect the matchup logic and identify where fill values should be masked before spatial matching.
This produces the error
ValueError Traceback (most recent call last)
Cell In[11], line 1
----> 1 get_ipython().run_cell_magic('time', '', 'res = pc.matchup(plan, \n variables = ["UVAerosolIndex"], \n open_method=discovr_epic_aer)\n')
File /srv/conda/envs/notebook/lib/python3.12/site-packages/IPython/core/interactiveshell.py:2572, in InteractiveShell.run_cell_magic(self, magic_name, line, cell)
2570 with self.builtin_trap:
2571 args = (magic_arg_s, cell)
-> 2572 result = fn(*args, **kwargs)
2574 # The code below prevents the output from being displayed
2575 # when using magics with decorator @output_can_be_silenced
2576 # when the last Python token in the expression is a ';'.
2577 if getattr(fn, magic.MAGIC_OUTPUT_CAN_BE_SILENCED, False):
File /srv/conda/envs/notebook/lib/python3.12/site-packages/IPython/core/magics/execution.py:1447, in ExecutionMagics.time(self, line, cell, local_ns)
1445 if interrupt_occured:
1446 if exit_on_interrupt and captured_exception:
-> 1447 raise captured_exception
1448 return
1449 return out
File /srv/conda/envs/notebook/lib/python3.12/site-packages/IPython/core/magics/execution.py:1411, in ExecutionMagics.time(self, line, cell, local_ns)
1409 st = clock2()
1410 try:
-> 1411 exec(code, glob, local_ns)
1412 out = None
1413 # multi-line %%time case
File :1
File ~/point-collocation/src/point_collocation/core/engine.py:283, in matchup(plan, open_method, variables, spatial_method, open_dataset_kwargs, silent, batch_size, save_dir, granule_range)
280 spec = _normalize_open_method(effective_open_method, open_dataset_kwargs)
282 effective_vars: list[str] = variables if variables is not None else plan.variables
--> 283 return _execute_plan(
284 plan,
285 spec=spec,
286 spatial_method=spatial_method,
287 variables=effective_vars,
288 silent=silent,
289 batch_size=batch_size,
290 save_dir=save_dir,
291 granule_range=granule_range,
292 )
File ~/point-collocation/src/point_collocation/core/engine.py:693, in _execute_plan(plan, spec, spatial_method, variables, silent, batch_size, save_dir, granule_range)
691 _extract_xoak_batch(ds, rows_for_granule, variables, lon_name, lat_name, time_dim)
692 else:
--> 693 _extract_ndpoint_batch(ds, rows_for_granule, variables, lon_name, lat_name, time_dim)
694 output_rows.extend(rows_for_granule)
695 batch_rows.extend(rows_for_granule)
File ~/point-collocation/src/point_collocation/core/engine.py:1263, in _extract_ndpoint_batch(ds, rows, variables, lon_name, lat_name, time_dim)
1258 ds_work[lon_name] = xr.DataArray(lon_2d, dims=lat_dims)
1260 # Build the NDPointIndex once for all query points using the built-in
1261 # scipy adapter (ScipyKDTreeAdapter). No tree_adapter_cls argument is
1262 # passed so xarray's default applies.
-> 1263 indexed_ds ...
📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.