Add group-level sign flipping and two custom ICA rejection steps - #22
Open
harrisonritz wants to merge 2 commits into
Open
Add group-level sign flipping and two custom ICA rejection steps#22harrisonritz wants to merge 2 commits into
harrisonritz wants to merge 2 commits into
Conversation
Adds `custom.osl`, an osl-ephys route over the same BIDS data the
mne-bids-pipeline route reads, running one subject per invocation so it
can be the body of a SLURM array job. Stages: preproc, source, all,
collate, validate, driven by a single YAML config per analysis.
Two source backends, since osl-ephys' LCMV path is written against RHINO
and therefore needs FSL (make_lcmv reads the forward from the RHINO file
tree, transform_recon_timeseries needs RHINO's transforms and calls
flirt, and resample_parcellation calls flirt too). Its
surface_extraction_method='freesurfer' path avoids FSL but only reaches
minimum-norm estimates:
rhino osl-ephys' native path; requires FSL.
freesurfer custom.osl.fs_bridge, reusing the existing recon-all output
and -trans.fif, beamforming with mne.beamformer.make_lcmv
and morphing to MNI via FreeSurfer's talairach.xfm. Parcel
time courses use osl-ephys' own maths, so output is
comparable with the RHINO backend. No FSL needed.
format_bids converts triggers to annotations and drops the stim channels,
so osl-ephys' find_events cannot be used; events_from_annotations rebuilds
the events array from raw.annotations instead, leaving format_bids
untouched. Codes come from the config's meta.event_codes so numbering is
stable across subjects, and descriptions with no annotations are dropped
because mne.Epochs rejects an event_id entry matching no event.
Group HTML reports are deferred to the collate stage. osl-ephys rebuilds
the shared subject_report.html at the end of every chain from inside its
own try/except, which in an array means every task writing one file and a
rendering hiccup failing an otherwise-successful subject.
The validate stage checks a config without touching data. It replicates
run_src_chain's argument check, which is stricter than it looks: it
rejects any wrapper declared (*args, **kwargs), so the
extract_fiducials_from_fif alias used by the osl-ephys tutorials cannot
be used in a config at all (use extract_polhemus_from_info).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fJPzRr6DvTdWL92Ffz2a5
custom.osl.sign_flip + custom.osl.group add a `group` stage that runs after
the per-subject array: pick a template subject, sign-flip every subject's
parcel time courses against it, then stack the flipped epochs into
(subjects x parcels x times) arrays per condition and form the configured
contrasts. A beamformer resolves each dipole's orientation only up to a sign,
independently per subject, so averaging without fixing that cancels the signal.
The flip search itself is osl-ephys'; the file handling around it is not,
because osl-ephys' own is broken for epoched data:
sign_flipping.apply_flips reads {outdir}/{subject}/parc/parc-epo.fif in its
epoched branch, while find_template_subject and fix_sign_ambiguity both write
and look for {source_method}-parc-epo.fif. The continuous branch gets the
prefix right; the epoched one does not, so fix_sign_ambiguity(epoched=True)
fails on a file that never existed. sign_flip.apply_flips is the corrected
equivalent, and writes separate *_sflip_*.fif files so re-runs never compound.
Two new preprocessing steps in custom.osl.extra_funcs:
ica_autoreject_safe osl-ephys' ica_autoreject with skip_if_absent.
find_bads_eog raises when there is no EOG channel,
which fails the whole chain; here it is skipped with a
warning, so a subject recorded without eye-tracking
does not need its own config. ECG is not guarded --
find_bads_ecg synthesises one from the magnetometers.
ica_kurtosisreject Marks components whose time course has excessive
kurtosis. Adapted from the osl-ephys
preprocessing_automatic tutorial, with two deliberate
departures: component time courses come from
ica.get_sources() (the unmixing matrix) rather than the
tutorial's get_components().T @ data (the mixing
matrix), which is not the component time course; and
BAD_* spans are excluded by default, since bad segments
are themselves the high-kurtosis spans.
validate now also checks the group section's contrasts, and the flip search is
parallelised across a local Dask cluster inside the one job.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013fJPzRr6DvTdWL92Ffz2a5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.