Skip to content

Commit

Permalink
Add peak velocity to FPGATrials.var_names; allow raise on empty mesos…
Browse files Browse the repository at this point in the history
…cope frame QC name
  • Loading branch information
k1o0 committed Oct 16, 2024
1 parent d71ac48 commit 136978f
Show file tree
Hide file tree
Showing 8 changed files with 13 additions and 27 deletions.
6 changes: 3 additions & 3 deletions ibllib/io/extractors/ephys_fpga.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def get_wheel_positions(sync, chmap, tmin=None, tmax=None):
A dictionary with keys ('timestamps', 'position'), containing the wheel event timestamps and
position in radians
Bunch
A dictionary of detected movement times with keys ('intervals', 'peakAmplitude', 'wheelMoves_peakVelocity_times').
A dictionary of detected movement times with keys ('intervals', 'peakAmplitude', 'peakVelocity_times').
"""
ts, pos = extract_wheel_sync(sync=sync, chmap=chmap, tmin=tmin, tmax=tmax)
moves = Bunch(extract_wheel_moves(ts, pos))
Expand Down Expand Up @@ -585,13 +585,13 @@ class FpgaTrials(extractors_base.BaseExtractor):
'_ibl_trials.stimOff_times.npy', None, None, None, '_ibl_trials.quiescencePeriod.npy',
'_ibl_trials.table.pqt', '_ibl_wheel.timestamps.npy',
'_ibl_wheel.position.npy', '_ibl_wheelMoves.intervals.npy',
'_ibl_wheelMoves.peakAmplitude.npy')
'_ibl_wheelMoves.peakAmplitude.npy', None)
var_names = ('goCueTrigger_times', 'stimOnTrigger_times',
'stimOffTrigger_times', 'stimFreezeTrigger_times', 'errorCueTrigger_times',
'errorCue_times', 'itiIn_times', 'stimFreeze_times', 'stimOff_times',
'valveOpen_times', 'phase', 'position', 'quiescence', 'table',
'wheel_timestamps', 'wheel_position',
'wheelMoves_intervals', 'wheelMoves_peakAmplitude')
'wheelMoves_intervals', 'wheelMoves_peakAmplitude', 'wheelMoves_peakVelocity_times')

bpod_rsync_fields = ('intervals', 'response_times', 'goCueTrigger_times',
'stimOnTrigger_times', 'stimOffTrigger_times',
Expand Down
10 changes: 2 additions & 8 deletions ibllib/io/extractors/training_wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def extract_wheel_moves(re_ts, re_pos, display=False):

# Put into dict
wheel_moves = {
'intervals': np.c_[on, off], 'peakAmplitude': amp, 'wheelMoves_peakVelocity_times': peak_vel}
'intervals': np.c_[on, off], 'peakAmplitude': amp, 'peakVelocity_times': peak_vel}
return wheel_moves


Expand All @@ -330,11 +330,6 @@ def extract_first_movement_times(wheel_moves, trials, min_qt=None):
gap between quiescence end and cue start, or during the quiescence period but sub-
threshold). The movement is sufficiently large if it is greater than or equal to THRESH.
:param wheel_moves:
:param trials: dictionary of trial data
:param min_qt:
:return: numpy array of
Parameters
----------
wheel_moves : dict
Expand Down Expand Up @@ -425,6 +420,5 @@ def _extract(self):
min_qt = self.settings.get('QUIESCENT_PERIOD', None)

first_moves, is_final, _ = extract_first_movement_times(moves, trials, min_qt=min_qt)
output = (ts, pos, moves['intervals'], moves['peakAmplitude'],
moves['wheelMoves_peakVelocity_times'], first_moves, is_final)
output = (ts, pos, moves['intervals'], moves['peakAmplitude'], moves['peakVelocity_times'], first_moves, is_final)
return output
3 changes: 1 addition & 2 deletions ibllib/pipes/mesoscope_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,7 @@ def _consolidate_exptQC(exptQC):

# Merge and make sure same indexes have same names across all files
frameQC_names_list = [e['frameQC_names'] for e in exptQC]
frameQC_names_list = [{k: i for i, k in enumerate(ensure_list(f)) if any(k)}
for f in frameQC_names_list]
frameQC_names_list = [{k: i for i, k in enumerate(ensure_list(f))} for f in frameQC_names_list]
frameQC_names = {k: v for d in frameQC_names_list for k, v in d.items()}
for d in frameQC_names_list:
for k, v in d.items():
Expand Down
8 changes: 2 additions & 6 deletions ibllib/qc/task_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
'response_times', 'rewardVolume', 'stimFreezeTrigger_times',
'stimFreeze_times', 'stimOffTrigger_times', 'stimOff_times',
'stimOnTrigger_times', 'stimOn_times', 'valveOpen_times',
'wheel_moves_intervals', 'wheel_moves_peak_amplitude',
'wheelMoves_intervals', 'wheelMoves_peakAmplitude', 'wheelMoves_peakVelocity_times',
'wheel_position', 'wheel_timestamps']


Expand Down Expand Up @@ -56,14 +56,10 @@ def rename_data(data):
if 'valveOpen_times' not in data:
data['valveOpen_times'] = data['feedback_times'].copy()
data['valveOpen_times'][~correct] = np.nan
if 'wheel_moves_intervals' not in data and 'wheelMoves_intervals' in data:
data['wheel_moves_intervals'] = data.pop('wheelMoves_intervals')
if 'wheel_moves_peak_amplitude' not in data and 'wheelMoves_peakAmplitude' in data:
data['wheel_moves_peak_amplitude'] = data.pop('wheelMoves_peakAmplitude')
data['correct'] = correct
diff_fields = list(set(REQUIRED_FIELDS).difference(set(data.keys())))
for miss_field in diff_fields:
data[miss_field] = data['feedback_times'] * np.nan
data[miss_field] = None if miss_field.startswith('wheel') else data['feedback_times'] * np.nan
if len(diff_fields):
_logger.warning(f'QC extractor, missing fields filled with NaNs: {diff_fields}')
return data
5 changes: 2 additions & 3 deletions ibllib/qc/task_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,9 +1111,8 @@ def check_n_trial_events(data, **_):
# test errorCueTrigger_times separately
# stimFreeze_times fails often due to TTL flicker
exclude = ['camera_timestamps', 'errorCueTrigger_times', 'errorCue_times',
'firstMovement_times', 'wheelMoves_peakVelocity_times', 'valveOpen_times',
'wheel_moves_peak_amplitude', 'wheel_moves_intervals', 'wheel_timestamps',
'wheel_intervals', 'stimFreeze_times']
'wheelMoves_peakVelocity_times', 'valveOpen_times', 'wheelMoves_peakAmplitude',
'wheelMoves_intervals', 'wheel_timestamps', 'stimFreeze_times']
events = [k for k in data.keys() if k.endswith('_times') and k not in exclude]
metric = np.zeros(data['intervals'].shape[0], dtype=bool)

Expand Down
4 changes: 2 additions & 2 deletions ibllib/tests/extractors/test_ephys_fpga.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ def test_extract_wheel_moves(self):
n = 56 # expected number of movements
self.assertTupleEqual(wheel_moves['intervals'].shape, (n, 2), 'failed to return the correct number of intervals')
self.assertEqual(wheel_moves['peakAmplitude'].size, n)
self.assertEqual(wheel_moves['wheelMoves_peakVelocity_times'].size, n)
self.assertEqual(wheel_moves['peakVelocity_times'].size, n)

# Check the first 3 intervals
ints = np.array([[24.78462599, 25.22562599], [29.58762599, 31.15062599], [31.64262599, 31.81662599]])
Expand All @@ -468,7 +468,7 @@ def test_extract_wheel_moves(self):
self.assertIsNone(np.testing.assert_allclose(actual, expected), 'unexpected amplitudes')

# Check peak velocities
actual = wheel_moves['wheelMoves_peakVelocity_times'][-3:]
actual = wheel_moves['peakVelocity_times'][-3:]
expected = [175.13662599, 176.65762599, 178.57262599]
self.assertIsNone(np.testing.assert_allclose(actual, expected), 'peak times')

Expand Down
2 changes: 1 addition & 1 deletion ibllib/tests/extractors/test_extractors.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ def test_size_outputs(self):
mock_data = {
'intervals': np.array([[0, 1], ]),
'peakAmplitude': np.array([1, 1]),
'wheelMoves_peakVelocity_times': np.array([1, 1])}
'peakVelocity_times': np.array([1, 1])}
function_name = 'ibllib.io.extractors.training_wheel.extract_wheel_moves'
# Training
with unittest.mock.patch(function_name, return_value=mock_data):
Expand Down
2 changes: 0 additions & 2 deletions ibllib/tests/test_mesoscope.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,6 @@ def test_consolidate_exptQC(self):
expected = ['ok', 'PMT off', 'galvos fault', 'high signal']
self.assertCountEqual(expected, frameQC_names['qc_labels'])

# Check with empty array (happens sometimes when converting .mat to .npy)
exptQC[1]['frameQC_names'] = np.r_[exptQC[1]['frameQC_names'], np.array([], dtype='<U1')]
# Check with single str instead of array
exptQC[1]['frameQC_names'] = 'ok'
frameQC, frameQC_names, bad_frames = self.task._consolidate_exptQC(exptQC)
Expand Down

0 comments on commit 136978f

Please sign in to comment.