Skip to content

Commit 0e78b96

Browse files
authored
Merge pull request #689 from int-brain-lab/hotfix/2.27.1
Correct handling of missing TTLs in FpgaTrialsHabituation
2 parents d875d82 + 8525c75 commit 0e78b96

File tree

5 files changed

+22
-25
lines changed

5 files changed

+22
-25
lines changed

ibllib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import logging
33
import warnings
44

5-
__version__ = '2.27'
5+
__version__ = '2.27.1'
66
warnings.filterwarnings('always', category=DeprecationWarning, module='ibllib')
77

88
# if this becomes a full-blown library we should let the logging configuration to the discretion of the dev

ibllib/io/extractors/ephys_fpga.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,7 +1376,6 @@ def build_trials(self, sync, chmap, display=False, **kwargs):
13761376
'intervals_1': bpod_event_intervals['trial_iti'][:, 0],
13771377
'goCue_times': audio_event_intervals['ready_tone'][:, 0]
13781378
})
1379-
n_trials = self.bpod_trials['intervals'].shape[0]
13801379

13811380
# Sync the Bpod clock to the DAQ.
13821381
self.bpod2fpga, drift_ppm, ibpod, ifpga = self.sync_bpod_clock(self.bpod_trials, fpga_events, self.sync_field)
@@ -1390,26 +1389,25 @@ def build_trials(self, sync, chmap, display=False, **kwargs):
13901389
# Assigning each event to a trial ensures exactly one event per trial (missing events are NaN)
13911390
assign_to_trial = partial(_assign_events_to_trial, fpga_events['intervals_0'])
13921391
trials = alfio.AlfBunch({
1393-
'goCue_times': assign_to_trial(fpga_events['goCue_times'], take='first')[:n_trials],
1394-
'feedback_times': assign_to_trial(fpga_events['feedback_times'])[:n_trials],
1395-
'stimCenter_times': assign_to_trial(self.frame2ttl['times'], take=-2)[:n_trials],
1396-
'stimOn_times': assign_to_trial(self.frame2ttl['times'], take='first')[:n_trials],
1397-
'stimOff_times': assign_to_trial(self.frame2ttl['times'])[:n_trials],
1392+
'goCue_times': assign_to_trial(fpga_events['goCue_times'], take='first'),
1393+
'feedback_times': assign_to_trial(fpga_events['feedback_times']),
1394+
'stimCenter_times': assign_to_trial(self.frame2ttl['times'], take=-2),
1395+
'stimOn_times': assign_to_trial(self.frame2ttl['times'], take='first'),
1396+
'stimOff_times': assign_to_trial(self.frame2ttl['times']),
13981397
})
1398+
out.update({k: trials[k][ifpga] for k in trials.keys()})
13991399

14001400
# If stim on occurs before trial end, use stim on time. Likewise for trial end and stim off
1401-
to_correct = ~np.isnan(trials['stimOn_times']) & (trials['stimOn_times'] < out['intervals'][:, 0])
1401+
to_correct = ~np.isnan(out['stimOn_times']) & (out['stimOn_times'] < out['intervals'][:, 0])
14021402
if np.any(to_correct):
14031403
_logger.warning('%i/%i stim on events occurring outside trial intervals', sum(to_correct), len(to_correct))
1404-
out['intervals'][to_correct, 0] = trials['stimOn_times'][to_correct]
1405-
to_correct = ~np.isnan(trials['stimOff_times']) & (trials['stimOff_times'] > out['intervals'][:, 1])
1404+
out['intervals'][to_correct, 0] = out['stimOn_times'][to_correct]
1405+
to_correct = ~np.isnan(out['stimOff_times']) & (out['stimOff_times'] > out['intervals'][:, 1])
14061406
if np.any(to_correct):
14071407
_logger.debug(
14081408
'%i/%i stim off events occurring outside trial intervals; using stim off times as trial end',
14091409
sum(to_correct), len(to_correct))
1410-
out['intervals'][to_correct, 1] = trials['stimOff_times'][to_correct]
1411-
1412-
out.update({k: trials[k][ifpga] for k in trials.keys()})
1410+
out['intervals'][to_correct, 1] = out['stimOff_times'][to_correct]
14131411

14141412
if display: # pragma: no cover
14151413
width = 0.5

ibllib/tests/qc/test_alignment_qc.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -266,16 +266,13 @@ class TestAlignmentQcManual(unittest.TestCase):
266266
@classmethod
267267
def setUpClass(cls) -> None:
268268
rng = np.random.default_rng()
269-
data = np.load(Path(Path(__file__).parent.parent.
270-
joinpath('fixtures', 'qc', 'data_alignmentqc_manual.npz')),
271-
allow_pickle=True)
269+
fixture_path = Path(__file__).parent.parent.joinpath('fixtures', 'qc')
270+
data = np.load(fixture_path / 'data_alignmentqc_manual.npz', allow_pickle=True)
272271
cls.xyz_picks = (data['xyz_picks'] * 1e6).tolist()
273272
cls.alignments = data['alignments'].tolist()
274273
cls.cluster_chns = data['cluster_chns']
275274

276-
data = np.load(Path(Path(__file__).parent.parent.
277-
joinpath('fixtures', 'qc', 'data_alignmentqc_existing.npz')),
278-
allow_pickle=True)
275+
data = np.load(fixture_path / 'data_alignmentqc_existing.npz', allow_pickle=True)
279276
insertion = data['insertion'].tolist()
280277
insertion['name'] = ''.join(random.choices(string.ascii_letters, k=5))
281278
insertion['json'] = {'xyz_picks': cls.xyz_picks}

ibllib/tests/test_oneibl.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,6 @@ def setUp(self) -> None:
272272
}
273273

274274
# makes sure tests start without session created
275-
eid = self.one.search(subject=self.subject, date_range='2018-04-01', query_type='remote')
276-
for ei in eid:
277-
self.one.alyx.rest('sessions', 'delete', id=ei)
278275
self.td = tempfile.TemporaryDirectory()
279276
self.session_path = Path(self.td.name).joinpath(self.subject, '2018-04-01', '002')
280277
self.alf_path = self.session_path.joinpath('alf')
@@ -506,12 +503,14 @@ def tearDown(self) -> None:
506503
# Delete weighings
507504
for w in self.one.alyx.rest('subjects', 'read', id=self.subject)['weighings']:
508505
self.one.alyx.rest('weighings', 'delete', id=w['url'].split('/')[-1])
506+
# Delete sessions
507+
eid = self.one.search(subject=self.subject, date_range='2018-04-01', query_type='remote')
508+
for ei in eid:
509+
self.one.alyx.rest('sessions', 'delete', id=ei)
509510

510511
@classmethod
511512
def tearDownClass(cls) -> None:
512-
# Note: datasets deleted in cascade
513-
for ses in cls.one.alyx.rest('sessions', 'list', subject=cls.subject, no_cache=True):
514-
cls.one.alyx.rest('sessions', 'delete', id=ses['url'][-36:])
513+
# Note: sessions and datasets deleted in cascade
515514
cls.one.alyx.rest('subjects', 'delete', id=cls.subject)
516515

517516

release_notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
- trainingPhaseChoiceWorld added to Bpod protocol extractor map fixture
1717
- Last trial of FPGA sessions now correctly extracted
1818
- Correct dynamic pipeline extraction of passive choice world trials
19+
#### 2.27.1
20+
- Correct handling of missing TTLs in FpgaTrialsHabituation
21+
1922

2023
### other
2124
- Removed deprecated pyschofit module

0 commit comments

Comments
 (0)