|
| 1 | +import pytest |
| 2 | + |
| 3 | +from spikeinterface.preprocessing import bandpass_filter, decimate |
| 4 | +from spikeinterface.exporters import export_to_ibl_gui |
| 5 | + |
| 6 | +from spikeinterface.exporters.tests.common import ( |
| 7 | + make_sorting_analyzer, |
| 8 | + sorting_analyzer_sparse_for_export, |
| 9 | +) |
| 10 | + |
| 11 | +required_output_files = [ |
| 12 | + "spikes.times.npy", |
| 13 | + "spikes.clusters.npy", |
| 14 | + "spikes.depths.npy", |
| 15 | + "spikes.amps.npy", |
| 16 | + "clusters.waveforms.npy", |
| 17 | + "clusters.peakToTrough.npy", |
| 18 | + "clusters.channels.npy", |
| 19 | + "clusters.metrics.csv", |
| 20 | + "channels.localCoordinates.npy", |
| 21 | + "channels.rawInd.npy", |
| 22 | +] |
| 23 | +ap_output_files = ["_iblqc_ephysTimeRmsAP.rms.npy", "_iblqc_ephysTimeRmsAP.timestamps.npy"] |
| 24 | +lfp_output_files = [ |
| 25 | + "_iblqc_ephysTimeRmsLF.rms.npy", |
| 26 | + "_iblqc_ephysTimeRmsLF.timestamps.npy", |
| 27 | + "_iblqc_ephysSpectralDensityLF.power.npy", |
| 28 | + "_iblqc_ephysSpectralDensityLF.freqs.npy", |
| 29 | +] |
| 30 | + |
| 31 | +good_units_query = "amplitude_median < -30" |
| 32 | + |
| 33 | + |
| 34 | +def test_export_ap_to_ibl(sorting_analyzer_sparse_for_export, create_cache_folder): |
| 35 | + cache_folder = create_cache_folder |
| 36 | + output_folder = cache_folder / "ibl_ap_output" |
| 37 | + |
| 38 | + sorting_analyzer = sorting_analyzer_sparse_for_export |
| 39 | + # AP, but no LFP |
| 40 | + export_to_ibl_gui( |
| 41 | + sorting_analyzer, |
| 42 | + output_folder, |
| 43 | + # good_units_query=good_units_query, |
| 44 | + verbose=True, |
| 45 | + n_jobs=-1, |
| 46 | + ) |
| 47 | + for f in required_output_files: |
| 48 | + assert (output_folder / f).exists(), f"Missing file: {f}" |
| 49 | + for f in ap_output_files: |
| 50 | + assert (output_folder / f).exists(), f"Missing file: {f}" |
| 51 | + for f in lfp_output_files: |
| 52 | + assert not (output_folder / f).exists(), f"Unexpected file: {f}" |
| 53 | + |
| 54 | + |
| 55 | +def test_export_recordingless_to_ibl(sorting_analyzer_sparse_for_export, create_cache_folder): |
| 56 | + cache_folder = create_cache_folder |
| 57 | + output_folder = cache_folder / "ibl_recordingless_output" |
| 58 | + |
| 59 | + sorting_analyzer = sorting_analyzer_sparse_for_export |
| 60 | + recording = sorting_analyzer.recording |
| 61 | + sorting_analyzer._recording = None |
| 62 | + |
| 63 | + # AP, but no LFP |
| 64 | + export_to_ibl_gui(sorting_analyzer_sparse_for_export, output_folder, good_units_query=good_units_query, n_jobs=-1) |
| 65 | + for f in required_output_files: |
| 66 | + assert (output_folder / f).exists(), f"Missing file: {f}" |
| 67 | + for f in ap_output_files: |
| 68 | + assert not (output_folder / f).exists(), f"Missing file: {f}" |
| 69 | + for f in lfp_output_files: |
| 70 | + assert not (output_folder / f).exists(), f"Unexpected file: {f}" |
| 71 | + |
| 72 | + sorting_analyzer._recording = recording |
| 73 | + |
| 74 | + |
| 75 | +def test_export_lfp_to_ibl(sorting_analyzer_sparse_for_export, create_cache_folder): |
| 76 | + cache_folder = create_cache_folder |
| 77 | + output_folder = cache_folder / "ibl_lfp_output" |
| 78 | + |
| 79 | + sorting_analyzer = sorting_analyzer_sparse_for_export |
| 80 | + recording = sorting_analyzer.recording |
| 81 | + recording_lfp = bandpass_filter(recording, freq_min=0.5, freq_max=300) |
| 82 | + recording_lfp = decimate(recording_lfp, 10) |
| 83 | + # LFP, but no AP |
| 84 | + export_to_ibl_gui( |
| 85 | + sorting_analyzer, output_folder, lfp_recording=recording_lfp, good_units_query=good_units_query, n_jobs=-1 |
| 86 | + ) |
| 87 | + for f in required_output_files: |
| 88 | + assert (output_folder / f).exists(), f"Missing file: {f}" |
| 89 | + for f in ap_output_files: |
| 90 | + assert (output_folder / f).exists(), f"Unexpected file: {f}" |
| 91 | + for f in lfp_output_files: |
| 92 | + assert (output_folder / f).exists(), f"Missing file: {f}" |
| 93 | + |
| 94 | + |
| 95 | +def test_missing_info(sorting_analyzer_sparse_for_export, create_cache_folder): |
| 96 | + cache_folder = create_cache_folder |
| 97 | + output_folder = cache_folder / "ibl_missing_info_output" |
| 98 | + |
| 99 | + sorting_analyzer = sorting_analyzer_sparse_for_export |
| 100 | + |
| 101 | + # missing metrics |
| 102 | + good_units_query = "rp_violations < 0.2" |
| 103 | + |
| 104 | + with pytest.raises(ValueError, match="Missing required quality metrics"): |
| 105 | + export_to_ibl_gui(sorting_analyzer, output_folder, good_units_query=good_units_query, n_jobs=-1) |
| 106 | + |
| 107 | + sorting_analyzer.delete_extension("spike_amplitudes") |
| 108 | + |
| 109 | + with pytest.raises(ValueError, match="Missing required extension"): |
| 110 | + export_to_ibl_gui(sorting_analyzer, output_folder, n_jobs=-1) |
| 111 | + |
| 112 | + |
| 113 | +if __name__ == "__main__": |
| 114 | + sorting_analyzer = make_sorting_analyzer(sparse=True) |
| 115 | + test_export_ap_to_ibl(sorting_analyzer) |
0 commit comments