Skip to content

Commit

Permalink
Merge pull request #689 from int-brain-lab/hotfix/2.27.1
Browse files Browse the repository at this point in the history
Correct handling of missing TTLs in FpgaTrialsHabituation
  • Loading branch information
k1o0 authored Dec 14, 2023
2 parents d875d82 + 8525c75 commit 0e78b96
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 25 deletions.
2 changes: 1 addition & 1 deletion ibllib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import logging
import warnings

__version__ = '2.27'
__version__ = '2.27.1'
warnings.filterwarnings('always', category=DeprecationWarning, module='ibllib')

# if this becomes a full-blown library we should let the logging configuration to the discretion of the dev
Expand Down
22 changes: 10 additions & 12 deletions ibllib/io/extractors/ephys_fpga.py
Original file line number Diff line number Diff line change
Expand Up @@ -1376,7 +1376,6 @@ def build_trials(self, sync, chmap, display=False, **kwargs):
'intervals_1': bpod_event_intervals['trial_iti'][:, 0],
'goCue_times': audio_event_intervals['ready_tone'][:, 0]
})
n_trials = self.bpod_trials['intervals'].shape[0]

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

# If stim on occurs before trial end, use stim on time. Likewise for trial end and stim off
to_correct = ~np.isnan(trials['stimOn_times']) & (trials['stimOn_times'] < out['intervals'][:, 0])
to_correct = ~np.isnan(out['stimOn_times']) & (out['stimOn_times'] < out['intervals'][:, 0])
if np.any(to_correct):
_logger.warning('%i/%i stim on events occurring outside trial intervals', sum(to_correct), len(to_correct))
out['intervals'][to_correct, 0] = trials['stimOn_times'][to_correct]
to_correct = ~np.isnan(trials['stimOff_times']) & (trials['stimOff_times'] > out['intervals'][:, 1])
out['intervals'][to_correct, 0] = out['stimOn_times'][to_correct]
to_correct = ~np.isnan(out['stimOff_times']) & (out['stimOff_times'] > out['intervals'][:, 1])
if np.any(to_correct):
_logger.debug(
'%i/%i stim off events occurring outside trial intervals; using stim off times as trial end',
sum(to_correct), len(to_correct))
out['intervals'][to_correct, 1] = trials['stimOff_times'][to_correct]

out.update({k: trials[k][ifpga] for k in trials.keys()})
out['intervals'][to_correct, 1] = out['stimOff_times'][to_correct]

if display: # pragma: no cover
width = 0.5
Expand Down
9 changes: 3 additions & 6 deletions ibllib/tests/qc/test_alignment_qc.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,16 +266,13 @@ class TestAlignmentQcManual(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
rng = np.random.default_rng()
data = np.load(Path(Path(__file__).parent.parent.
joinpath('fixtures', 'qc', 'data_alignmentqc_manual.npz')),
allow_pickle=True)
fixture_path = Path(__file__).parent.parent.joinpath('fixtures', 'qc')
data = np.load(fixture_path / 'data_alignmentqc_manual.npz', allow_pickle=True)
cls.xyz_picks = (data['xyz_picks'] * 1e6).tolist()
cls.alignments = data['alignments'].tolist()
cls.cluster_chns = data['cluster_chns']

data = np.load(Path(Path(__file__).parent.parent.
joinpath('fixtures', 'qc', 'data_alignmentqc_existing.npz')),
allow_pickle=True)
data = np.load(fixture_path / 'data_alignmentqc_existing.npz', allow_pickle=True)
insertion = data['insertion'].tolist()
insertion['name'] = ''.join(random.choices(string.ascii_letters, k=5))
insertion['json'] = {'xyz_picks': cls.xyz_picks}
Expand Down
11 changes: 5 additions & 6 deletions ibllib/tests/test_oneibl.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,6 @@ def setUp(self) -> None:
}

# makes sure tests start without session created
eid = self.one.search(subject=self.subject, date_range='2018-04-01', query_type='remote')
for ei in eid:
self.one.alyx.rest('sessions', 'delete', id=ei)
self.td = tempfile.TemporaryDirectory()
self.session_path = Path(self.td.name).joinpath(self.subject, '2018-04-01', '002')
self.alf_path = self.session_path.joinpath('alf')
Expand Down Expand Up @@ -506,12 +503,14 @@ def tearDown(self) -> None:
# Delete weighings
for w in self.one.alyx.rest('subjects', 'read', id=self.subject)['weighings']:
self.one.alyx.rest('weighings', 'delete', id=w['url'].split('/')[-1])
# Delete sessions
eid = self.one.search(subject=self.subject, date_range='2018-04-01', query_type='remote')
for ei in eid:
self.one.alyx.rest('sessions', 'delete', id=ei)

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


Expand Down
3 changes: 3 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
- trainingPhaseChoiceWorld added to Bpod protocol extractor map fixture
- Last trial of FPGA sessions now correctly extracted
- Correct dynamic pipeline extraction of passive choice world trials
#### 2.27.1
- Correct handling of missing TTLs in FpgaTrialsHabituation


### other
- Removed deprecated pyschofit module
Expand Down

0 comments on commit 0e78b96

Please sign in to comment.