@@ -35,11 +35,18 @@ class OpenEphys:
35
35
def __init__ (self , experiment_dir ):
36
36
self .session_dir = pathlib .Path (experiment_dir )
37
37
38
- openephys_file = pyopenephys .File (self .session_dir .parent ) # this is on the Record Node level
38
+ if self .session_dir .name .startswith ('recording' ):
39
+ openephys_file = pyopenephys .File (self .session_dir .parent .parent ) # this is on the Record Node level
40
+ self ._is_recording_folder = True
41
+ else :
42
+ openephys_file = pyopenephys .File (self .session_dir .parent ) # this is on the Record Node level
43
+ self ._is_recording_folder = False
39
44
40
45
# extract the "recordings" for this session
41
46
self .experiment = next (experiment for experiment in openephys_file .experiments
42
- if pathlib .Path (experiment .absolute_foldername ) == self .session_dir )
47
+ if pathlib .Path (experiment .absolute_foldername ) == (
48
+ self .session_dir .parent if self ._is_recording_folder else self .session_dir )
49
+ )
43
50
44
51
# extract probe data
45
52
self .probes = self .load_probe_data ()
@@ -76,26 +83,39 @@ def load_probe_data(self):
76
83
if isinstance (sigchain ['PROCESSOR' ], list )
77
84
else [sigchain ['PROCESSOR' ]])
78
85
for processor in processor_iter :
79
- if processor ['@pluginName' ] in ('Neuropix-PXI' , 'Neuropix-3a' ):
86
+ if processor ['@pluginName' ] in ('Neuropix-3a' , 'Neuropix-PXI' ):
87
+ if 'STREAM' in processor : # only on version >= 0.6.0
88
+ ap_streams = [stream for stream in processor ['STREAM' ] if not stream ['@name' ].endswith ('LFP' )]
89
+ else :
90
+ ap_streams = None
91
+
80
92
if (processor ['@pluginName' ] == 'Neuropix-3a'
81
93
or 'NP_PROBE' not in processor ['EDITOR' ]):
82
94
if isinstance (processor ['EDITOR' ]['PROBE' ], dict ):
83
- probe = Probe (processor , 0 )
84
- probes [probe .probe_SN ] = probe
95
+ probe_indices = (0 ,)
85
96
else :
86
- for probe_index in range (len (processor ['EDITOR' ]['PROBE' ])):
87
- probe = Probe (processor , probe_index )
88
- probes [probe .probe_SN ] = probe
89
- else : # Neuropix-PXI
90
- for probe_index in range (len (processor ['EDITOR' ]['NP_PROBE' ])):
91
- probe = Probe (processor , probe_index )
92
- probes [probe .probe_SN ] = probe
93
-
97
+ probe_indices = range (len (processor ['EDITOR' ]['PROBE' ]))
98
+ elif processor ['@pluginName' ] == 'Neuropix-PXI' :
99
+ probe_indices = range (len (processor ['EDITOR' ]['NP_PROBE' ]))
100
+ else :
101
+ raise NotImplementedError
102
+ else : # not a processor for Neuropixels probe
103
+ continue
104
+
105
+ for probe_index in probe_indices :
106
+ probe = Probe (processor , probe_index )
107
+ if ap_streams :
108
+ probe .probe_info ['ap_stream' ] = ap_streams [probe_index ]
109
+ probes [probe .probe_SN ] = probe
110
+
94
111
for probe_index , probe_SN in enumerate (probes ):
95
112
96
113
probe = probes [probe_SN ]
97
114
98
115
for rec in self .experiment .recordings :
116
+ if self ._is_recording_folder and rec .absolute_foldername != self .session_dir :
117
+ continue
118
+
99
119
assert len (rec ._oebin ['continuous' ]) == len (rec .analog_signals ), \
100
120
f'Mismatch in the number of continuous data' \
101
121
f' - expecting { len (rec ._oebin ["continuous" ])} (from structure.oebin file),' \
@@ -106,17 +126,26 @@ def load_probe_data(self):
106
126
if continuous_info ['source_processor_id' ] != probe .processor_id :
107
127
continue
108
128
109
- # determine if this is continuous data for AP or LFP
110
- if 'source_processor_sub_idx' in continuous_info :
129
+ # determine if this is continuous data for AP or LFP for the current probe
130
+ if 'ap_stream' in probe .probe_info :
131
+ if probe .probe_info ['ap_stream' ]['@name' ].split ('-' )[0 ] != continuous_info ['stream_name' ].split ('-' )[0 ]:
132
+ continue # not continuous data for the current probe
133
+ match = re .search ('-(AP|LFP)$' , continuous_info ['stream_name' ])
134
+ if match :
135
+ continuous_type = match .groups ()[0 ].lower ()
136
+ else :
137
+ continuous_type = 'ap'
138
+ elif 'source_processor_sub_idx' in continuous_info :
111
139
if continuous_info ['source_processor_sub_idx' ] == probe_index * 2 : # ap data
112
140
assert continuous_info ['sample_rate' ] == analog_signal .sample_rate == 30000
113
141
continuous_type = 'ap'
114
142
elif continuous_info ['source_processor_sub_idx' ] == probe_index * 2 + 1 : # lfp data
115
143
assert continuous_info ['sample_rate' ] == analog_signal .sample_rate == 2500
116
144
continuous_type = 'lfp'
145
+ else :
146
+ continue # not continuous data for the current probe
117
147
else :
118
- match = re .search ('-(AP|LFP)$' , continuous_info ['folder_name' ].strip ('/' ))
119
- continuous_type = match .groups ()[0 ].lower ()
148
+ raise ValueError (f'Unable to infer type (AP or LFP) for the continuous data from:\n \t { continuous_info } ' )
120
149
121
150
if continuous_type == 'ap' :
122
151
probe .recording_info ['recording_count' ] += 1
@@ -179,6 +208,15 @@ def __init__(self, processor, probe_index=0):
179
208
self .probe_info = processor ['EDITOR' ]['NP_PROBE' ][probe_index ]
180
209
self .probe_SN = self .probe_info ['@probe_serial_number' ]
181
210
self .probe_model = _probe_model_name_mapping [self .probe_info ['@probe_name' ]]
211
+
212
+ if 'ELECTRODE_XPOS' in self .probe_info :
213
+ self .probe_info ['ELECTRODE_XPOS' ] = {int (re .search (r'\d+$' , k ).group ()): int (v )
214
+ for k , v in self .probe_info .pop ('ELECTRODE_XPOS' ).items ()}
215
+ self .probe_info ['ELECTRODE_YPOS' ] = {int (re .search (r'\d+$' , k ).group ()): int (v )
216
+ for k , v in self .probe_info .pop ('ELECTRODE_YPOS' ).items ()}
217
+ self .probe_info ['ELECTRODE_SHANK' ] = {int (re .search (r'\d+$' , k ).group ()): int (v )
218
+ for k , v in self .probe_info ['CHANNELS' ].items ()}
219
+
182
220
self ._channels_connected = {int (re .search (r'\d+$' , k ).group ()): 1
183
221
for k in self .probe_info .pop ('CHANNELS' )}
184
222
0 commit comments