Skip to content

Commit 13d74ad

Browse files
committed
Merge branch 'run_kilosort' of https://github.com/datajoint/element-array-ephys into rk
2 parents 70e0b1c + d298b07 commit 13d74ad

File tree

4 files changed

+69
-24
lines changed

4 files changed

+69
-24
lines changed

element_array_ephys/ephys_acute.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def make(self, key):
407407
for key in electrode_query.fetch('KEY')}
408408

409409
electrode_keys.extend(probe_electrodes[channel_idx]
410-
for channel_idx in oe_probe.lfp_meta['channels_indices'])
410+
for channel_idx in lfp_channel_ind)
411411
else:
412412
raise NotImplementedError(f'LFP extraction from acquisition software'
413413
f' of type {acq_software} is not yet implemented')
@@ -428,7 +428,8 @@ class ClusteringMethod(dj.Lookup):
428428
clustering_method_desc: varchar(1000)
429429
"""
430430

431-
contents = [('kilosort2.5', 'kilosort2.5 clustering method'),
431+
contents = [('kilosort2', 'kilosort2 clustering method'),
432+
('kilosort2.5', 'kilosort2.5 clustering method'),
432433
('kilosort3', 'kilosort3 clustering method')]
433434

434435

element_array_ephys/ephys_chronic.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
import numpy as np
55
import inspect
66
import importlib
7+
from decimal import Decimal
78

89
from element_interface.utils import find_root_directory, find_full_path, dict_to_uuid
910

1011
from .readers import spikeglx, kilosort, openephys
11-
from . import probe
12+
from . import probe, get_logger
13+
14+
15+
log = get_logger(__name__)
1216

1317
schema = dj.schema()
1418

@@ -350,7 +354,7 @@ def make(self, key):
350354
for key in electrode_query.fetch('KEY')}
351355

352356
electrode_keys.extend(probe_electrodes[channel_idx]
353-
for channel_idx in oe_probe.lfp_meta['channels_indices'])
357+
for channel_idx in lfp_channel_ind)
354358
else:
355359
raise NotImplementedError(f'LFP extraction from acquisition software'
356360
f' of type {acq_software} is not yet implemented')
@@ -371,7 +375,8 @@ class ClusteringMethod(dj.Lookup):
371375
clustering_method_desc: varchar(1000)
372376
"""
373377

374-
contents = [('kilosort2.5', 'kilosort2.5 clustering method'),
378+
contents = [('kilosort2', 'kilosort2 clustering method'),
379+
('kilosort2.5', 'kilosort2.5 clustering method'),
375380
('kilosort3', 'kilosort3 clustering method')]
376381

377382

element_array_ephys/ephys_no_curation.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ def make(self, key):
406406
for key in electrode_query.fetch('KEY')}
407407

408408
electrode_keys.extend(probe_electrodes[channel_idx]
409-
for channel_idx in oe_probe.lfp_meta['channels_indices'])
409+
for channel_idx in lfp_channel_ind)
410410
else:
411411
raise NotImplementedError(f'LFP extraction from acquisition software'
412412
f' of type {acq_software} is not yet implemented')
@@ -427,7 +427,8 @@ class ClusteringMethod(dj.Lookup):
427427
clustering_method_desc: varchar(1000)
428428
"""
429429

430-
contents = [('kilosort2.5', 'kilosort2.5 clustering method'),
430+
contents = [('kilosort2', 'kilosort2 clustering method'),
431+
('kilosort2.5', 'kilosort2.5 clustering method'),
431432
('kilosort3', 'kilosort3 clustering method')]
432433

433434

element_array_ephys/readers/openephys.py

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,18 @@ class OpenEphys:
3535
def __init__(self, experiment_dir):
3636
self.session_dir = pathlib.Path(experiment_dir)
3737

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
3944

4045
# extract the "recordings" for this session
4146
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+
)
4350

4451
# extract probe data
4552
self.probes = self.load_probe_data()
@@ -76,26 +83,39 @@ def load_probe_data(self):
7683
if isinstance(sigchain['PROCESSOR'], list)
7784
else [sigchain['PROCESSOR']])
7885
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+
8092
if (processor['@pluginName'] == 'Neuropix-3a'
8193
or 'NP_PROBE' not in processor['EDITOR']):
8294
if isinstance(processor['EDITOR']['PROBE'], dict):
83-
probe = Probe(processor, 0)
84-
probes[probe.probe_SN] = probe
95+
probe_indices = (0,)
8596
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+
94111
for probe_index, probe_SN in enumerate(probes):
95112

96113
probe = probes[probe_SN]
97114

98115
for rec in self.experiment.recordings:
116+
if self._is_recording_folder and rec.absolute_foldername != self.session_dir:
117+
continue
118+
99119
assert len(rec._oebin['continuous']) == len(rec.analog_signals), \
100120
f'Mismatch in the number of continuous data' \
101121
f' - expecting {len(rec._oebin["continuous"])} (from structure.oebin file),' \
@@ -106,17 +126,26 @@ def load_probe_data(self):
106126
if continuous_info['source_processor_id'] != probe.processor_id:
107127
continue
108128

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:
111139
if continuous_info['source_processor_sub_idx'] == probe_index * 2: # ap data
112140
assert continuous_info['sample_rate'] == analog_signal.sample_rate == 30000
113141
continuous_type = 'ap'
114142
elif continuous_info['source_processor_sub_idx'] == probe_index * 2 + 1: # lfp data
115143
assert continuous_info['sample_rate'] == analog_signal.sample_rate == 2500
116144
continuous_type = 'lfp'
145+
else:
146+
continue # not continuous data for the current probe
117147
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}')
120149

121150
if continuous_type == 'ap':
122151
probe.recording_info['recording_count'] += 1
@@ -179,6 +208,15 @@ def __init__(self, processor, probe_index=0):
179208
self.probe_info = processor['EDITOR']['NP_PROBE'][probe_index]
180209
self.probe_SN = self.probe_info['@probe_serial_number']
181210
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+
182220
self._channels_connected = {int(re.search(r'\d+$', k).group()): 1
183221
for k in self.probe_info.pop('CHANNELS')}
184222

0 commit comments

Comments
 (0)