@@ -103,6 +103,9 @@ def get_trace_margin(self):
103103 def get_dtype (self ):
104104 return base_peak_dtype
105105
106+ def get_peak_slice (self , segment_index , start_frame , end_frame , ):
107+ # not needed for PeakDetector
108+ raise NotImplementedError
106109
107110# this is used in sorting components
108111class PeakDetector (PeakSource ):
@@ -127,11 +130,18 @@ def get_trace_margin(self):
127130 def get_dtype (self ):
128131 return base_peak_dtype
129132
130- def compute (self , traces , start_frame , end_frame , segment_index , max_margin ):
131- # get local peaks
133+ def get_peak_slice (self , segment_index , start_frame , end_frame , max_margin ):
132134 sl = self .segment_slices [segment_index ]
133135 peaks_in_segment = self .peaks [sl ]
134136 i0 , i1 = np .searchsorted (peaks_in_segment ["sample_index" ], [start_frame , end_frame ])
137+ return i0 , i1
138+
139+ def compute (self , traces , start_frame , end_frame , segment_index , max_margin , peak_slice ):
140+ # get local peaks
141+ sl = self .segment_slices [segment_index ]
142+ peaks_in_segment = self .peaks [sl ]
143+ # i0, i1 = np.searchsorted(peaks_in_segment["sample_index"], [start_frame, end_frame])
144+ i0 , i1 = peak_slice
135145 local_peaks = peaks_in_segment [i0 :i1 ]
136146
137147 # make sample index local to traces
@@ -212,8 +222,7 @@ def get_trace_margin(self):
212222 def get_dtype (self ):
213223 return self ._dtype
214224
215- def compute (self , traces , start_frame , end_frame , segment_index , max_margin ):
216- # get local peaks
225+ def get_peak_slice (self , segment_index , start_frame , end_frame , max_margin ):
217226 sl = self .segment_slices [segment_index ]
218227 peaks_in_segment = self .peaks [sl ]
219228 if self .include_spikes_in_margin :
@@ -222,6 +231,20 @@ def compute(self, traces, start_frame, end_frame, segment_index, max_margin):
222231 )
223232 else :
224233 i0 , i1 = np .searchsorted (peaks_in_segment ["sample_index" ], [start_frame , end_frame ])
234+ return i0 , i1
235+
236+ def compute (self , traces , start_frame , end_frame , segment_index , max_margin , peak_slice ):
237+ # get local peaks
238+ sl = self .segment_slices [segment_index ]
239+ peaks_in_segment = self .peaks [sl ]
240+ # if self.include_spikes_in_margin:
241+ # i0, i1 = np.searchsorted(
242+ # peaks_in_segment["sample_index"], [start_frame - max_margin, end_frame + max_margin]
243+ # )
244+ # else:
245+ # i0, i1 = np.searchsorted(peaks_in_segment["sample_index"], [start_frame, end_frame])
246+ i0 , i1 = peak_slice
247+
225248 local_peaks = peaks_in_segment [i0 :i1 ]
226249
227250 # make sample index local to traces
@@ -525,64 +548,79 @@ def _compute_peak_pipeline_chunk(segment_index, start_frame, end_frame, worker_c
525548 nodes = worker_ctx ["nodes" ]
526549
527550 recording_segment = recording ._recording_segments [segment_index ]
528- traces_chunk , left_margin , right_margin = get_chunk_with_margin (
529- recording_segment , start_frame , end_frame , None , max_margin , add_zeros = True
530- )
531-
532- # compute the graph
533- pipeline_outputs = {}
534- for node in nodes :
535- node_parents = node .parents if node .parents else list ()
536- node_input_args = tuple ()
537- for parent in node_parents :
538- parent_output = pipeline_outputs [parent ]
539- parent_outputs_tuple = parent_output if isinstance (parent_output , tuple ) else (parent_output ,)
540- node_input_args += parent_outputs_tuple
541- if isinstance (node , PeakDetector ):
542- # to handle compatibility peak detector is a special case
543- # with specific margin
544- # TODO later when in master: change this later
545- extra_margin = max_margin - node .get_trace_margin ()
546- if extra_margin :
547- trace_detection = traces_chunk [extra_margin :- extra_margin ]
551+ node0 = nodes [0 ]
552+
553+ if isinstance (node0 , (SpikeRetriever , PeakRetriever )):
554+ # in this case PeakSource could have no peaks and so no need to load traces just skip
555+ peak_slice = i0 , i1 = node0 .get_peak_slice (segment_index , start_frame , end_frame , max_margin )
556+ load_trace_and_compute = i0 < i1
557+ else :
558+ # PeakDetector always need traces
559+ load_trace_and_compute = True
560+
561+ if load_trace_and_compute :
562+ traces_chunk , left_margin , right_margin = get_chunk_with_margin (
563+ recording_segment , start_frame , end_frame , None , max_margin , add_zeros = True
564+ )
565+ # compute the graph
566+ pipeline_outputs = {}
567+ for node in nodes :
568+ node_parents = node .parents if node .parents else list ()
569+ node_input_args = tuple ()
570+ for parent in node_parents :
571+ parent_output = pipeline_outputs [parent ]
572+ parent_outputs_tuple = parent_output if isinstance (parent_output , tuple ) else (parent_output ,)
573+ node_input_args += parent_outputs_tuple
574+ if isinstance (node , PeakDetector ):
575+ # to handle compatibility peak detector is a special case
576+ # with specific margin
577+ # TODO later when in master: change this later
578+ extra_margin = max_margin - node .get_trace_margin ()
579+ if extra_margin :
580+ trace_detection = traces_chunk [extra_margin :- extra_margin ]
581+ else :
582+ trace_detection = traces_chunk
583+ node_output = node .compute (trace_detection , start_frame , end_frame , segment_index , max_margin )
584+ # set sample index to local
585+ node_output [0 ]["sample_index" ] += extra_margin
586+ elif isinstance (node , PeakSource ):
587+ node_output = node .compute (traces_chunk , start_frame , end_frame , segment_index , max_margin , peak_slice )
548588 else :
549- trace_detection = traces_chunk
550- node_output = node .compute (trace_detection , start_frame , end_frame , segment_index , max_margin )
551- # set sample index to local
552- node_output [ 0 ][ "sample_index" ] += extra_margin
553- elif isinstance ( node , PeakSource ):
554- node_output = node . compute ( traces_chunk , start_frame , end_frame , segment_index , max_margin )
555- else :
556- # TODO later when in master: change the signature of all nodes (or maybe not!)
557- node_output = node .compute ( traces_chunk , * node_input_args )
558- pipeline_outputs [node ] = node_output
559-
560- # propagate the output
561- pipeline_outputs_tuple = tuple ()
562- for node in nodes :
563- # handle which buffer are given to the output
564- # this is controlled by node.return_output being a bool or tuple of bool
565- out = pipeline_outputs [ node ]
566- if isinstance ( out , tuple ) :
567- if isinstance (node .return_output , bool ) and node .return_output :
568- pipeline_outputs_tuple += out
569- elif isinstance (node .return_output , tuple ):
570- for flag , e in zip ( node . return_output , out ):
571- if flag :
572- pipeline_outputs_tuple += ( e ,)
573- else :
574- if isinstance ( node . return_output , bool ) and node . return_output :
575- pipeline_outputs_tuple += ( out ,)
576- elif isinstance ( node . return_output , tuple ):
577- # this should not apppend : maybe a checker somewhere before ?
578- pass
589+ # TODO later when in master: change the signature of all nodes (or maybe not!)
590+ node_output = node .compute (traces_chunk , * node_input_args )
591+ pipeline_outputs [ node ] = node_output
592+
593+ # propagate the output
594+ pipeline_outputs_tuple = tuple ( )
595+ for node in nodes :
596+ # handle which buffer are given to the output
597+ # this is controlled by node.return_output being a bool or tuple of bool
598+ out = pipeline_outputs [node ]
599+ if isinstance ( out , tuple ):
600+ if isinstance ( node . return_output , bool ) and node . return_output :
601+ pipeline_outputs_tuple += out
602+ elif isinstance ( node . return_output , tuple ) :
603+ for flag , e in zip ( node . return_output , out ):
604+ if flag :
605+ pipeline_outputs_tuple += ( e ,)
606+ else :
607+ if isinstance (node .return_output , bool ) and node .return_output :
608+ pipeline_outputs_tuple += ( out ,)
609+ elif isinstance (node .return_output , tuple ):
610+ # this should not apppend : maybe a checker somewhere before ?
611+ pass
612+
613+ if isinstance ( nodes [ 0 ], PeakDetector ) :
614+ # the first out element is the peak vector
615+ # we need to go back to absolut sample index
616+ pipeline_outputs_tuple [ 0 ][ "sample_index" ] += start_frame - left_margin
617+
618+ return pipeline_outputs_tuple
579619
580- if isinstance (nodes [0 ], PeakDetector ):
581- # the first out element is the peak vector
582- # we need to go back to absolut sample index
583- pipeline_outputs_tuple [0 ]["sample_index" ] += start_frame - left_margin
620+ else :
621+ # the gather will skip this output and not concatenate it
622+ return
584623
585- return pipeline_outputs_tuple
586624
587625
588626class GatherToMemory :
@@ -595,6 +633,9 @@ def __init__(self):
595633 self .tuple_mode = None
596634
597635 def __call__ (self , res ):
636+ if res is None :
637+ return
638+
598639 if self .tuple_mode is None :
599640 # first loop only
600641 self .tuple_mode = isinstance (res , tuple )
@@ -655,6 +696,9 @@ def __init__(self, folder, names, npy_header_size=1024, exist_ok=False):
655696 self .final_shapes .append (None )
656697
657698 def __call__ (self , res ):
699+ if res is None :
700+ return
701+
658702 if self .tuple_mode is None :
659703 # first loop only
660704 self .tuple_mode = isinstance (res , tuple )
0 commit comments