Skip to content

Handle empty annulus in local common reference - #4728

Open
adityasingh2400 wants to merge 1 commit into
SpikeInterface:mainfrom
adityasingh2400:fix-4193-empty-annulus
Open

Handle empty annulus in local common reference#4728
adityasingh2400 wants to merge 1 commit into
SpikeInterface:mainfrom
adityasingh2400:fix-4193-empty-annulus

Conversation

@adityasingh2400

Copy link
Copy Markdown

Fixes #4193

Building a common_reference recording with reference="local" raises ZeroDivisionError: division by zero whenever a channel has no other channel beyond the exclude (inner) radius. A tetrode reproduces it with the default local_radius=(30, 55), since all four contacts sit within 30 um of each other:

rec = generate_recording(num_channels=4, durations=[1.0], set_probe=False)
rec.set_dummy_probe_from_locations(np.array([[0., 0.], [0., 20.], [20., 0.], [20., 20.]]))
common_reference(rec, reference="local", local_radius=(30., 55.))  # ZeroDivisionError

The root cause is in the kernel construction. When the annulus holds fewer than min_local_neighbors channels, the code falls back to the closest channels beyond the inner radius, then unconditionally does local_kernel[i, neighbors_i] = 1 / len(neighbors_i). That fallback normally finds something, but if nothing lies beyond the inner radius at all then neighbors_i is empty and the division blows up. The user only sees a bare ZeroDivisionError with no indication that the radius is the problem.

The fix follows what @alejoe91 suggested in the issue. Channels with no available neighbor keep their kernel row at zero, which leaves them unreferenced, and a warning naming those channels is raised at init. The average operator already computes a zero shift from a zero kernel row, so only the median branch needed a guard: an empty neighborhood there would have produced nan from np.median of an empty slice, so it now passes the trace through unchanged.

Tested with four new cases in test_common_reference.py, parametrized over both operators. The first covers the tetrode geometry where every channel is unreferenced, the second a cross layout where only the center channel has nothing beyond the radius while the four arms are still referenced to their opposite arm. All four fail on main (two with ZeroDivisionError at construction, two with DID NOT WARN) and pass with the fix. The full test_common_reference.py file passes, 11 passed and 1 skipped.

When no channel lies beyond the exclude radius, the local kernel row was
built with an empty neighbor list, so 1 / len(neighbors_i) raised a
ZeroDivisionError at init. Such channels are now left unreferenced and a
warning is raised instead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local referencing cannot handle empty annulus

1 participant