Skip to content

Commit a0b1cd1

Browse files
committed
STart refactor template matcghing into noepieline
1 parent 4ab6223 commit a0b1cd1

7 files changed

Lines changed: 599 additions & 263 deletions

File tree

src/spikeinterface/core/node_pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def compute(self, traces, start_frame, end_frame, segment_index, max_margin, *ar
9696

9797

9898
class PeakSource(PipelineNode):
99-
# base class for peak detector
99+
# base class for peak detector or template matching
100100
def get_trace_margin(self):
101101
raise NotImplementedError
102102

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import numpy as np
2+
from spikeinterface.core import Templates
3+
from spikeinterface.core.node_pipeline import PeakSource
4+
5+
_base_matching_dtype = [
6+
("sample_index", "int64"),
7+
("channel_index", "int64"),
8+
("cluster_index", "int64"),
9+
("amplitude", "float64"),
10+
("segment_index", "int64"),
11+
]
12+
13+
class BaseTemplateMatching(PeakSource):
14+
def __init__(self, recording, templates, return_output=True, parents=None):
15+
# TODO make a sharedmem of template here
16+
# TODO maybe check that channel_id are the same with recording
17+
18+
assert isinstance(d["templates"], Templates), (
19+
f"The templates supplied is of type {type(d['templates'])} " f"and must be a Templates"
20+
)
21+
self.templates = templates
22+
PeakSource.__init__(self, recording, return_output=return_output, parents=parents)
23+
24+
def get_dtype(self):
25+
return np.dtype(_base_matching_dtype)
26+
27+
def get_trace_margin(self):
28+
raise NotImplementedError
29+
30+
def compute(self, traces, start_frame, end_frame, segment_index, max_margin, *args):
31+
raise NotImplementedError

src/spikeinterface/sortingcomponents/matching/main.py

Lines changed: 158 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
from threadpoolctl import threadpool_limits
44
import numpy as np
55

6-
from spikeinterface.core.job_tools import ChunkRecordingExecutor, fix_job_kwargs
7-
from spikeinterface.core import get_chunk_with_margin
6+
# from spikeinterface.core.job_tools import ChunkRecordingExecutor, fix_job_kwargs
7+
# from spikeinterface.core import get_chunk_with_margin
8+
9+
from spikeinterface.core.job_tools import fix_job_kwargs
10+
from spikeinterface.core.node_pipeline import run_node_pipeline
11+
812

913

1014
def find_spikes_from_templates(
@@ -42,117 +46,174 @@ def find_spikes_from_templates(
4246
job_kwargs = fix_job_kwargs(job_kwargs)
4347

4448
method_class = matching_methods[method]
49+
node0 = method_class(recording, **method_kwargs)
50+
nodes = [node0]
4551

46-
# initialize
47-
method_kwargs = method_class.initialize_and_check_kwargs(recording, method_kwargs)
48-
49-
# add
50-
method_kwargs["margin"] = method_class.get_margin(recording, method_kwargs)
51-
52-
# serialiaze for worker
53-
method_kwargs_seralized = method_class.serialize_method_kwargs(method_kwargs)
54-
55-
# and run
56-
func = _find_spikes_chunk
57-
init_func = _init_worker_find_spikes
58-
init_args = (recording, method, method_kwargs_seralized)
59-
processor = ChunkRecordingExecutor(
52+
spikes = run_node_pipeline(
6053
recording,
61-
func,
62-
init_func,
63-
init_args,
64-
handle_returns=True,
54+
nodes,
55+
job_kwargs,
6556
job_name=f"find spikes ({method})",
66-
verbose=verbose,
67-
**job_kwargs,
57+
gather_mode="memory",
58+
squeeze_output=True,
6859
)
69-
spikes = processor.run()
70-
71-
spikes = np.concatenate(spikes)
72-
7360
if extra_outputs:
61+
# TODO deprecated extra_outputs
62+
method_kwargs = {}
7463
return spikes, method_kwargs
7564
else:
7665
return spikes
7766

7867

79-
def _init_worker_find_spikes(recording, method, method_kwargs):
80-
"""Initialize worker for finding spikes."""
8168

82-
from .method_list import matching_methods
69+
# def find_spikes_from_templates(
70+
# recording, method="naive", method_kwargs={}, extra_outputs=False, verbose=False, **job_kwargs
71+
# ) -> np.ndarray | tuple[np.ndarray, dict]:
72+
# """Find spike from a recording from given templates.
8373

84-
method_class = matching_methods[method]
85-
method_kwargs = method_class.unserialize_in_worker(method_kwargs)
74+
# Parameters
75+
# ----------
76+
# recording : RecordingExtractor
77+
# The recording extractor object
78+
# method : "naive" | "tridesclous" | "circus" | "circus-omp" | "wobble", default: "naive"
79+
# Which method to use for template matching
80+
# method_kwargs : dict, optional
81+
# Keyword arguments for the chosen method
82+
# extra_outputs : bool
83+
# If True then method_kwargs is also returned
84+
# **job_kwargs : dict
85+
# Parameters for ChunkRecordingExecutor
86+
# verbose : Bool, default: False
87+
# If True, output is verbose
8688

87-
# create a local dict per worker
88-
worker_ctx = {}
89-
worker_ctx["recording"] = recording
90-
worker_ctx["method"] = method
91-
worker_ctx["method_kwargs"] = method_kwargs
92-
worker_ctx["function"] = method_class.main_function
89+
# Returns
90+
# -------
91+
# spikes : ndarray
92+
# Spikes found from templates.
93+
# method_kwargs:
94+
# Optionaly returns for debug purpose.
9395

94-
return worker_ctx
96+
# """
97+
# from .method_list import matching_methods
9598

99+
# assert method in matching_methods, f"The 'method' {method} is not valid. Use a method from {matching_methods}"
96100

97-
def _find_spikes_chunk(segment_index, start_frame, end_frame, worker_ctx):
98-
"""Find spikes from a chunk of data."""
101+
# job_kwargs = fix_job_kwargs(job_kwargs)
99102

100-
# recover variables of the worker
101-
recording = worker_ctx["recording"]
102-
method = worker_ctx["method"]
103-
method_kwargs = worker_ctx["method_kwargs"]
104-
margin = method_kwargs["margin"]
103+
# method_class = matching_methods[method]
105104

106-
# load trace in memory given some margin
107-
recording_segment = recording._recording_segments[segment_index]
108-
traces, left_margin, right_margin = get_chunk_with_margin(
109-
recording_segment, start_frame, end_frame, None, margin, add_zeros=True
110-
)
105+
# # initialize
106+
# method_kwargs = method_class.initialize_and_check_kwargs(recording, method_kwargs)
107+
108+
# # add
109+
# method_kwargs["margin"] = method_class.get_margin(recording, method_kwargs)
110+
111+
# # serialiaze for worker
112+
# method_kwargs_seralized = method_class.serialize_method_kwargs(method_kwargs)
113+
114+
# # and run
115+
# func = _find_spikes_chunk
116+
# init_func = _init_worker_find_spikes
117+
# init_args = (recording, method, method_kwargs_seralized)
118+
# processor = ChunkRecordingExecutor(
119+
# recording,
120+
# func,
121+
# init_func,
122+
# init_args,
123+
# handle_returns=True,
124+
# job_name=f"find spikes ({method})",
125+
# verbose=verbose,
126+
# **job_kwargs,
127+
# )
128+
# spikes = processor.run()
129+
130+
# spikes = np.concatenate(spikes)
131+
132+
# if extra_outputs:
133+
# return spikes, method_kwargs
134+
# else:
135+
# return spikes
136+
137+
138+
139+
140+
# def _init_worker_find_spikes(recording, method, method_kwargs):
141+
# """Initialize worker for finding spikes."""
142+
143+
# from .method_list import matching_methods
144+
145+
# method_class = matching_methods[method]
146+
# method_kwargs = method_class.unserialize_in_worker(method_kwargs)
147+
148+
# # create a local dict per worker
149+
# worker_ctx = {}
150+
# worker_ctx["recording"] = recording
151+
# worker_ctx["method"] = method
152+
# worker_ctx["method_kwargs"] = method_kwargs
153+
# worker_ctx["function"] = method_class.main_function
154+
155+
# return worker_ctx
156+
157+
158+
# def _find_spikes_chunk(segment_index, start_frame, end_frame, worker_ctx):
159+
# """Find spikes from a chunk of data."""
160+
161+
# # recover variables of the worker
162+
# recording = worker_ctx["recording"]
163+
# method = worker_ctx["method"]
164+
# method_kwargs = worker_ctx["method_kwargs"]
165+
# margin = method_kwargs["margin"]
166+
167+
# # load trace in memory given some margin
168+
# recording_segment = recording._recording_segments[segment_index]
169+
# traces, left_margin, right_margin = get_chunk_with_margin(
170+
# recording_segment, start_frame, end_frame, None, margin, add_zeros=True
171+
# )
172+
173+
# function = worker_ctx["function"]
174+
175+
# with threadpool_limits(limits=1):
176+
# spikes = function(traces, method_kwargs)
177+
178+
# # remove spikes in margin
179+
# if margin > 0:
180+
# keep = (spikes["sample_index"] >= margin) & (spikes["sample_index"] < (traces.shape[0] - margin))
181+
# spikes = spikes[keep]
182+
183+
# spikes["sample_index"] += start_frame - margin
184+
# spikes["segment_index"] = segment_index
185+
# return spikes
186+
187+
188+
# # generic class for template engine
189+
# class BaseTemplateMatchingEngine:
190+
# default_params = {}
191+
192+
# @classmethod
193+
# def initialize_and_check_kwargs(cls, recording, kwargs):
194+
# """This function runs before loops"""
195+
# # need to be implemented in subclass
196+
# raise NotImplementedError
111197

112-
function = worker_ctx["function"]
113-
114-
with threadpool_limits(limits=1):
115-
spikes = function(traces, method_kwargs)
116-
117-
# remove spikes in margin
118-
if margin > 0:
119-
keep = (spikes["sample_index"] >= margin) & (spikes["sample_index"] < (traces.shape[0] - margin))
120-
spikes = spikes[keep]
121-
122-
spikes["sample_index"] += start_frame - margin
123-
spikes["segment_index"] = segment_index
124-
return spikes
125-
126-
127-
# generic class for template engine
128-
class BaseTemplateMatchingEngine:
129-
default_params = {}
130-
131-
@classmethod
132-
def initialize_and_check_kwargs(cls, recording, kwargs):
133-
"""This function runs before loops"""
134-
# need to be implemented in subclass
135-
raise NotImplementedError
136-
137-
@classmethod
138-
def serialize_method_kwargs(cls, kwargs):
139-
"""This function serializes kwargs to distribute them to workers"""
140-
# need to be implemented in subclass
141-
raise NotImplementedError
142-
143-
@classmethod
144-
def unserialize_in_worker(cls, recording, kwargs):
145-
"""This function unserializes kwargs in workers"""
146-
# need to be implemented in subclass
147-
raise NotImplementedError
148-
149-
@classmethod
150-
def get_margin(cls, recording, kwargs):
151-
# need to be implemented in subclass
152-
raise NotImplementedError
153-
154-
@classmethod
155-
def main_function(cls, traces, method_kwargs):
156-
"""This function returns the number of samples for the chunk margins"""
157-
# need to be implemented in subclass
158-
raise NotImplementedError
198+
# @classmethod
199+
# def serialize_method_kwargs(cls, kwargs):
200+
# """This function serializes kwargs to distribute them to workers"""
201+
# # need to be implemented in subclass
202+
# raise NotImplementedError
203+
204+
# @classmethod
205+
# def unserialize_in_worker(cls, recording, kwargs):
206+
# """This function unserializes kwargs in workers"""
207+
# # need to be implemented in subclass
208+
# raise NotImplementedError
209+
210+
# @classmethod
211+
# def get_margin(cls, recording, kwargs):
212+
# # need to be implemented in subclass
213+
# raise NotImplementedError
214+
215+
# @classmethod
216+
# def main_function(cls, traces, method_kwargs):
217+
# """This function returns the number of samples for the chunk margins"""
218+
# # need to be implemented in subclass
219+
# raise NotImplementedError
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from __future__ import annotations
22

33
from .naive import NaiveMatching
4-
from .tdc import TridesclousPeeler
5-
from .circus import CircusPeeler, CircusOMPSVDPeeler
6-
from .wobble import WobbleMatch
4+
# from .tdc import TridesclousPeeler
5+
# from .circus import CircusPeeler, CircusOMPSVDPeeler
6+
# from .wobble import WobbleMatch
77

88
matching_methods = {
99
"naive": NaiveMatching,
1010
"tdc-peeler": TridesclousPeeler,
11-
"circus": CircusPeeler,
12-
"circus-omp-svd": CircusOMPSVDPeeler,
13-
"wobble": WobbleMatch,
11+
# "circus": CircusPeeler,
12+
# "circus-omp-svd": CircusOMPSVDPeeler,
13+
# "wobble": WobbleMatch,
1414
}

0 commit comments

Comments
 (0)