1818import scipy .io as sio
1919from os .path import exists
2020
21- from ieegprep .bids import load_channel_info , load_stim_event_info , load_ieeg_sidecar
21+ from ieegprep .bids . sidecars import load_channel_info , load_elec_stim_events , load_ieeg_sidecar
2222from ieegprep .bids .data_epoch import load_data_epochs_averages
2323from ieegprep .bids .rereferencing import RerefStruct
2424from ieegprep .utils .console import multi_line_list , print_progressbar
@@ -303,79 +303,45 @@ def process_subset(bids_subset_data_path, output_dir, preproc_prioritize_speed=F
303303
304304
305305 #
306- # retrieve trials
306+ # retrieve trials (onsets) and stim-pairs conditions
307307 #
308308
309- # retrieve the stimulation events (onsets and pairs) from the events.tsv file
309+ # retrieve the electrical stimulation events (onsets and stim-pairs) from the events.tsv file
310+ # only retrieve the stim-pairs for the channels that are included
310311 try :
311- trial_onsets , trial_pairs , trials_bad_onsets = load_stim_event_info (bids_subset_root + '_events.tsv' )
312+ trial_onsets , trial_pairs , stim_pairs_onsets , bad_trial_onsets = load_elec_stim_events (bids_subset_root + '_events.tsv' ,
313+ exclude_bad_events = True ,
314+ concat_bidirectional_stimpairs = cfg ('trials' , 'concat_bidirectional_pairs' ),
315+ only_stimpairs_between_channels = channels_stim_incl )
312316 except (RuntimeError ):
313- logging .error ('Could not load the stimulation event metadata (\' ' + bids_subset_root + '_events.tsv\' ), exiting...' )
314- raise RuntimeError ('Could not load the stimulation event metadata' )
317+ logging .error ('Could not load the electrical stimulation event metadata (\' ' + bids_subset_root + '_events.tsv\' ), exiting...' )
318+ raise RuntimeError ('Could not load the electrical stimulation event metadata' )
315319
316- if len (trials_bad_onsets ) > 0 :
317- log_indented_line ('Number of trials marked as bad (excluded):' , str (len (trials_bad_onsets )))
320+ if len (bad_trial_onsets ) > 0 :
321+ log_indented_line ('Number of trials marked as bad (excluded):' , str (len (bad_trial_onsets )))
318322
319323 # check if there are trials
320324 if len (trial_onsets ) == 0 :
321325 logging .error ('No trials were found, exiting...' )
322326 raise RuntimeError ('No trials found' )
323327
324-
325- #
326- # retrieve stimulus-pairs
327- #
328-
329- # determine the stimulation-pairs conditions (and the trial and electrodes that belong to them)
330- # (note that the 'concat_bidirectional_pairs' configuration setting is taken into account here)
331- #
332- stim_pairs_onsets = dict () # for each pair, the onsets of the trials that were involved
333- stim_pairs_electrode_names = dict () # for each pair, the names of the electrodes that were stimulated
334-
335- # TODO: there might be a difference in the type of channels included for stimulation and those for recording
336-
337- # loop over all the combinations of channels
338- # Note: only the combinations of stim-pairs that actually have events/trials end up in the output
339- for iChannel0 in range (len (channels_stim_incl )):
340- for iChannel1 in range (len (channels_stim_incl )):
341-
342- # retrieve the indices of all the trials that concern this stim-pair
343- indices = []
344- if cfg ('trials' , 'concat_bidirectional_pairs' ):
345- # allow concatenation of bidirectional pairs, pair order does not matter
346- if not iChannel1 < iChannel0 :
347- # unique pairs while ignoring pair order
348- indices = [i for i , x in enumerate (trial_pairs ) if
349- (x [0 ] == channels_stim_incl [iChannel0 ] and x [1 ] == channels_stim_incl [iChannel1 ]) or (x [0 ] == channels_stim_incl [iChannel1 ] and x [1 ] == channels_stim_incl [iChannel0 ])]
350-
351- else :
352- # do not concatenate bidirectional pairs, pair order matters
353- indices = [i for i , x in enumerate (trial_pairs ) if
354- x [0 ] == channels_stim_incl [iChannel0 ] and x [1 ] == channels_stim_incl [iChannel1 ]]
355-
356- # add the pair if there are trials for it
357- if len (indices ) > 0 :
358- stim_pairs_onsets [channels_stim_incl [iChannel0 ] + '-' + channels_stim_incl [iChannel1 ]] = [trial_onsets [i ] for i in indices ]
359- stim_pairs_electrode_names [channels_stim_incl [iChannel0 ] + '-' + channels_stim_incl [iChannel1 ]] = (channels_stim_incl [iChannel0 ], channels_stim_incl [iChannel1 ])
360-
361- # search for stimulus-pairs with too little trials
362- stimpair_remove_indices = []
328+ # determine the stimulus-pairs conditions that have too little trials
329+ stimpair_remove_keys = []
363330 for stim_pair , onsets in stim_pairs_onsets .items ():
364331 if len (onsets ) < cfg ('trials' , 'minimum_stimpair_trials' ):
365- stimpair_remove_indices .append (stim_pair )
332+ stimpair_remove_keys .append (stim_pair )
366333
367334 # remove the stimulus-pairs with too little trials
368- if len (stimpair_remove_indices ) > 0 :
335+ if len (stimpair_remove_keys ) > 0 :
369336
370337 # message
371- stimpair_print = [stim_pair + ' (' + str (len (stim_pairs_onsets [stim_pair ])) + ' trials)' for stim_pair in stimpair_remove_indices ]
338+ stimpair_print = [stim_pair + ' (' + str (len (stim_pairs_onsets [stim_pair ])) + ' trials)' for stim_pair in stimpair_remove_keys ]
372339 stimpair_print = [str_print .ljust (len (max (stimpair_print , key = len )), ' ' ) for str_print in stimpair_print ]
373340 logging .info (multi_line_list (stimpair_print , LOGGING_CAPTION_INDENT_LENGTH , 'Stim-pairs excluded by number of trials:' , 3 , ' ' ))
374341
375342 # remove those stimulation-pairs
376- for stim_pair in stimpair_remove_indices :
343+ for stim_pair in stimpair_remove_keys :
377344 del stim_pairs_onsets [stim_pair ]
378- del stim_pairs_electrode_names [stim_pair ]
379345
380346 # display stimulation-pair/trial information
381347 stimpair_print = [stim_pair + ' (' + str (len (onsets )) + ' trials)' for stim_pair , onsets in stim_pairs_onsets .items ()]
@@ -391,11 +357,11 @@ def process_subset(bids_subset_data_path, output_dir, preproc_prioritize_speed=F
391357 if early_reref is not None :
392358 early_reref .set_exclude_reref_epochs (stim_pairs_onsets ,
393359 (cfg ('preprocess' , 'early_re_referencing' , 'stim_excl_epoch' )[0 ], cfg ('preprocess' , 'early_re_referencing' , 'stim_excl_epoch' )[1 ]),
394- '-' )
360+ channel_key_seperator = '-' )
395361 if late_reref is not None :
396362 late_reref .set_exclude_reref_epochs (stim_pairs_onsets ,
397363 (cfg ('preprocess' , 'late_re_referencing' , 'stim_excl_epoch' )[0 ], cfg ('preprocess' , 'late_re_referencing' , 'stim_excl_epoch' )[1 ]),
398- '-' )
364+ channel_key_seperator = '-' )
399365 logging .info ('' )
400366
401367
@@ -421,7 +387,7 @@ def process_subset(bids_subset_data_path, output_dir, preproc_prioritize_speed=F
421387 # TODO: normalize to raw or to Z-values (return both raw and z?)
422388 # z-might be needed for detection
423389 try :
424- sampling_rate , averages , metrics = load_data_epochs_averages (bids_subset_data_path , channels_measured_incl , list ( stim_pairs_onsets . values ()) ,
390+ sampling_rate , averages , metrics = load_data_epochs_averages (bids_subset_data_path , channels_measured_incl , stim_pairs_onsets ,
425391 trial_epoch = cfg ('trials' , 'trial_epoch' ),
426392 baseline_norm = cfg ('trials' , 'baseline_norm' ),
427393 baseline_epoch = cfg ('trials' , 'baseline_epoch' ),
@@ -437,24 +403,21 @@ def process_subset(bids_subset_data_path, output_dir, preproc_prioritize_speed=F
437403 raise RuntimeError ('Could not load data' )
438404
439405 # for each stimulation pair condition, NaN out the values of the measured electrodes that were stimulated
440- iPair = 0
441- for stim_pair in stim_pairs_onsets . keys ():
406+ for stim_pair_index , stim_pair in enumerate ( stim_pairs_onsets ):
407+ stim_pair_electrode_names = stim_pair . split ( '-' )
442408
443409 # find and clear the first electrode
444410 try :
445- averages [channels_measured_incl .index (stim_pairs_electrode_names [ stim_pair ][ 0 ]), iPair , :] = np .nan
411+ averages [channels_measured_incl .index (stim_pair_electrode_names [ 0 ]), stim_pair_index , :] = np .nan
446412 except ValueError :
447413 pass
448414
449415 # find and clear the second electrode
450416 try :
451- averages [channels_measured_incl .index (stim_pairs_electrode_names [ stim_pair ][ 1 ]), iPair , :] = np .nan
417+ averages [channels_measured_incl .index (stim_pair_electrode_names [ 1 ]), stim_pair_index , :] = np .nan
452418 except ValueError :
453419 pass
454420
455- # next stim-pair index
456- iPair += 1
457-
458421 # determine the sample of stimulus onset (counting from the epoch start)
459422 onset_sample = int (round (abs (cfg ('trials' , 'trial_epoch' )[0 ] * sampling_rate )))
460423 # todo: handle trial epochs which start after the trial onset, currently disallowed by config
@@ -468,6 +431,7 @@ def process_subset(bids_subset_data_path, output_dir, preproc_prioritize_speed=F
468431 metric_counter += 1
469432 if cfg ('metrics' , 'waveform' , 'enabled' ):
470433 waveform_metrics = metrics [:, :, metric_counter ]
434+ metric_counter += 1
471435
472436
473437 #
0 commit comments