The current repository stores codes used for stimulus presentation and analyzing Eplink data (Phase II, Phase III, and TWH) along with a detailed walkthrough of the preprocesing and analysis.
Table of Contents
Raw data and derivatives are available in BIDS format on Nibi (Alliance Canada), under the CoNCH lab's allocation:
| dataset | path | notes |
|---|---|---|
| EpLink3 (Phase III) | /project/6033493/datasets/EpLink3 |
dataset_description.json calls it EpLink_merged: combines the original EpLink3 cohort (syngo MR E11) with an additional healthy-control cohort, EpLink_newHC (syngo MR XA60). Cohort is recorded per-subject in participants.tsv. freesurfer/fmriprep derivatives already present as per-subject tar.gz (see below). |
| EpLink2 (Phase II) | /project/6033493/datasets/EpLink2/rawdata |
Raw BIDS data only; freesurfer/fmriprep derivatives have not yet been generated under this allocation. |
Each dataset directory follows the same layout, which the pipeline's config templates against (config/snakebids.yml):
/project/6033493/datasets/<dataset>/
├── participants.tsv
├── dataset_description.json
└── derivatives/
├── freesurfer-7.2.0/sub-<id>_freesurfer-7.2.0.tar.gz
└── fmriprep-20.2.6/sub-<id>_fmriprep-20.2.6.tar.gz
Which dataset is processed is controlled entirely by the dataset: key in config/snakebids.yml (currently EpLink3) — it gets substituted into every {dataset}-templated path in the config (participants_tsv, freesurfer_tar, fmriprep_tar, archive_dir, ...).
This data is collected from epileptic patients, and age and sex matched healthy controls at the Centre for Functional and Metabolic Mapping, Western University, London, Ontario. The dataset consists of a structural scan and three naturalistic tasks: a resting state and a movie watching task. The movie was Bang! You're Dead by Alfred Hitchcock (hitchcock). The following table summarizes the acquisition parameters for the tasks:
| run | # Volumes | TR (ms) | TE (ms) | Slice Thickness (mm) |
|---|---|---|---|---|
| rest | 175 | 2200 | 30 | 3.7 |
| hitchcock | 246 | 2000 | 30 | 3 |
The pipeline reads datasets from the CoNCH lab's Alliance Canada allocation (/project/6033493/..., account rrg-conchlab_cpu) and submits SLURM jobs on Nibi — you need an active Alliance Canada account with access to that allocation before anything else here will work (ask the PI if you don't have this yet).
Clone the repo on Nibi (e.g. into your /scratch/<username> space, since that's where the pipeline's results/ outputs land):
git clone https://github.com/CoNCHLab-Github/Eplink.git
use squeue or sq command to list Slurm jobs. squeue supplies information about all jobs in the system, by default. You can use the shorter sq to list only your own jobs. Find more details here.
- create a directory for the mount if you don't have one:
mkdir ~/Nibi - use sshfs to mount as a directory on computecanada file system:
sshfs <username>@nibi.sharcnet.ca:/home/<username> ~/Nibi - You will be asked for your password and 2FA if applicable.
The ISC pipeline's Python environment (snakemake, snakebids, nilearn, etc.) and its run commands are managed by pixi — dependencies are pinned in pixi.toml/pixi.lock so the environment is reproducible across machines.
- Install pixi once (works on Nibi or locally):
curl -fsSL https://pixi.sh/install.sh | bash - From the repo root, create the environment:
pixi install - Run any pipeline command through pixi — it resolves and activates the environment automatically, no manual
source activate/venvstep needed:pixi run <task> - See the full list of available tasks with
pixi task list, or read the[tasks]table inpixi.toml. Tasks are described in Step 3 below. - An optional
devenvironment (pytest,ipython,jupyterlab) is available viapixi run -e dev <task>.
wb_command (Connectome Workbench) is not installed via pixi. On Nibi it's loaded as an environment module — the module name is set by wb_module in config/snakebids.yml (default: connectome-workbench; find the exact name with module spider connectome). Rules that call wb_command also load apptainer alongside it (some wb_command operations shell out to a containerized helper), and Snakemake loads both modules automatically for SLURM-submitted jobs because the profile sets use-envmodules: true (see Step 3).
Datasets were analyzed in freesurfer version 7.2. regularBatch from neuroglia-helpers was used to submit recon-all jobs for each participant to compute canada.
regularBatch <script_name> <participants_list_text> -b <before-args> -a <after-args> -j <job-template>
regularBatch takes the following options for passing arguments to pipeline script:
- -b /args/ : cmd-line arguments that go before the subject id
- -a /args/ : cmd-line arguments that go after the subject id
regularBatch ./run_freesurfer_bids_7.2 subjects.txt -a "\"path/to/bids path/to/output\"" -j 8core32gb12h
run_freesurfer_bids_7.2: script that runs freesurfer recon-all for one subject (available in this repository).subjects.txt: stores the subjects IDs that is going to be analyzed. You can change this file to rerun freesurfer on arbitrary subjects. One subject id in each line including the 'sub-' (example for all phase III subjects is included in this repository).-a "\"path/to/bids path/to/output\"": passes both bids and output directories to the script as one argument (space seperated).-j 8core32gb12h: specifies job template for each participant (8 cores, 32GB RAM, 12 hours)
Example command for phase II
regularBatch ./run_freesurfer_bids_7.2 subjects.txt -a "\"/project/6050199/akhanf/cfmm-bids/data/Peters/tle3T_phase2/bids /scratch/alit/eplink-p2-freesurfer\"" -j 8core32gb12h
Datasets were preprocessed by the fMRIprep pipeline version 20.2.6. bidsBatch from neuroglia-helpers was used to submit fMRIprep jobs for each participant to compute canada.
bidsBatch <bidsBatch options> <app_name> <bids_dir> <output_dir> <participant/group> <app options>
- For the full list of available apps run
bidsBatchcommand. - Find a full list of fMRIprep options here.
bidsBatch fmriprep_20.2.6 <bids_dir> <output_dir> participant --output-spaces MNI152NLin2009cAsym T1w --fs-subjects-dir <freesurfer_output_dir>
<bids_dir>and<output_dir>can be relative or absolute paths to raw data and output folder.- fMRIprep option
--output-spacesis set to generate outputs in both native (T1w) and MNI template spaces (MNI152NLin2009cAsym). --fs-subjects-diris the path to freesurfer output (default: OUTPUT_DIR/freesurfer).
To pull the fMRIprep reports properly on your local machine to review run the fetch_fMRIprep_reports.sh script (included in the repository). You might need to adjust the fMRIprep output path in the script. This script assumes that Nibi is mounted as a file system at ~/Nibi, if it isn't check here for instructions.
The inter-subject correlation pipeline is implemented as a snakebids-wrapped Snakemake workflow: workflow/Snakefile (rules) + config/snakebids.yml (dataset selection, parcellations, confounds, smoothing levels, etc.). All commands are run through pixi run <task> (see pixi setup), which activates the pinned environment for you — no manual venv/module activation needed for the Python side.
pixi install # once, creates the pinned environment
pixi run dry-run # sanity-check the DAG (snakemake -n)
pixi run extract-fmriprep # one-time: untar fmriprep derivatives (see below)
pixi run run # submit the rest of the pipeline to SLURM
workflow/profiles/slurm/config.yaml is a Snakemake 8 executor profile built on snakemake-executor-plugin-slurm (pinned in pixi.toml). Every pixi run pipeline task passes --profile workflow/profiles/slurm to snakemake, so when you invoke it snakemake:
- resolves the DAG of missing output files for the target rule,
- submits each job individually to SLURM (
sbatch) underslurm_account: rrg-conchlab_cpu, - applies default resources (
mem_mb: 32000,cpus_per_task: 8,runtime: 60min) unless a rule overrides them in its ownresources:block in the Snakefile, - loads environment modules (e.g.
wb_command) for rules that declareenvmodules:, since the profile setsuse-envmodules: true, - retries failed jobs twice (
retries: 2) and keeps unrelated jobs running on failure (keep-going: true), - runs up to 100 jobs concurrently (
jobs: 100).
You do not write or submit an sbatch script yourself — run pixi run run (or any of the stage-specific tasks below) from a login node or inside regularInteractive, and Snakemake handles submission, polling, and resubmission for every rule. Use squeue/sq (see above) to watch the submitted jobs.
Each stage has a dry-<stage> (adds --dry-run) and a <stage> (submits for real) pixi task:
| stage | snakemake target | pixi tasks | what it does | output path |
|---|---|---|---|---|
| fMRIprep extraction | extract_fmriprep_all |
dry-extract-fmriprep, extract-fmriprep |
untars each subject's fmriprep-20.2.6 derivatives tar into results/{dataset}/fmriprep/. Must run once before the rest of the pipeline — later rules read from this extracted directory. |
results/{dataset}/fmriprep/ |
| denoising | denoise_all |
dry-denoise, denoise |
nilearn-based confound regression on the T1w-space preprocessed BOLD (workflow/scripts/denoise.py), per confound set in config["confounds"]. |
results/{dataset}/denoised/ |
| surfaces | gen_midthickness_all |
dry-surfaces, surfaces |
extracts freesurfer surfaces from freesurfer_tar, converts white/pial to GIFTI directly in scanner-RAS space (via mris_convert --to-scanner), and builds native-space midthickness surfaces (needs the freesurfer container + wb_command). |
results/{dataset}/surfaces/ |
| resampling | resample2fsLR_all |
dry-fslr, fslr |
projects denoised volumes onto the native surface, then resamples to fsLR 32k. | results/{dataset}/resampled2fsLR32k/ |
| smoothing | smooth_all |
dry-smooth, smooth |
surface smoothing at each fwhm in config["fwhm"] (FWHM is converted to sigma before being passed to wb_command). |
results/{dataset}/smoothed/ |
| parcellation | parcellate_original_all |
dry-parcellate, parcellate |
averages resampled (or temporally-resampled) surface data within each config["parcellations"] atlas. |
results/{dataset}/{source}-parcellated/{atlas}/ |
| ISC | ISC_all |
dry-isc, isc |
pairwise and leave-one-out ISC (vertex-level and per-parcellation). | results/{dataset}/pwISC/ |
| ISC significance (SWB) | pwISC_bootstrap_movie |
dry-pwisc-swb, pwisc-swb |
subject-wise bootstrap significance testing (Chen et al., 2016) on the pairwise ISC from pw_ISC, run over every parcellation atlas and every smoothing level (vertex-level included), excluding QC-flagged subjects (config["subjid_exclude"]). Vertex-level (atlas=none) jobs get a longer SLURM runtime since the bootstrap loop isn't yet optimized for that many units — see the PERF TODO in workflow/scripts/pwISC_bootstrap.py. |
results/{dataset}/pwISC_stats/ |
| functional connectivity | fc_all |
dry-fc, fc |
pearson correlation FC matrices per parcellation atlas, per confound set, resampled and non-resampled. | results/{dataset}/FC/{atlas}/ |
| archiving | archive_results |
dry-archive, archive |
packages results/{dataset} into a SquashFS image at {archive_dir}/{archive_file} (both templated on {dataset}, project space). Re-running after adding subjects appends to the existing image rather than overwriting it (no -noappend). |
archive_dir/archive_file (project space) |
| retrieval | retrieve_archive |
dry-retrieve, retrieve |
extracts the archived SquashFS image back into results/{dataset} (unsquashfs -f, so it merges into/overwrites anything already there). Not wired into the main DAG on purpose — it won't trigger archive_results if the archive doesn't exist yet. |
results/{dataset} |
| everything | (default target) | dry-run, run |
runs the full DAG up to the pipeline's default target. | — |
| DAG visualization | — | dag |
snakemake --dag | dot -Tsvg > dag.svg |
— |
Offloading subjects from scratch: the subject list for every stage is discovered from what's physically present in
results/{dataset}/fmriprep(not fromparticipants.tsv) — deleting a subject'sfmriprep/sub-Xfolder drops them out of every later stage's target list too. When freeing scratch space after archiving, delete a subject's data from everyresults/{dataset}/*subfolder, includingfmriprep/sub-X. If you leavefmriprep/sub-Xin place but remove a downstream folder (e.g.denoised/sub-X), the subject is still discovered and Snakemake will try to regenerate the now-missing downstream output instead of leaving them archived.
Parcellations
Here is a list of available parcellations:
Note 1: Desikan, Glasser, and Schaefer atlas files were adopted form this repository.
Note 2: Yan 2023 parcellations come in CIFTI format and were converted to .gii using wb_command:
wb_command -cifti-separate <input>.dlabel.nii COLUMN -label CORTEX_LEFT <output_L>.label.gii -label CORTEX_RIGHT <output_R>.label.gii
ISC significance testing (SWB)
n_perm_bootstrap (config/snakebids.yml) sets the number of subject-wise bootstrap resamples used by pwISC_bootstrap (default 10000); bootstrap_seed fixes the RNG seed for reproducibility (leave blank for a random seed per run). subjid_exclude lists subject IDs to drop from the significance test (e.g. QC failures), matching the exclusions applied in notebooks/pairwise_summary.ipynb.
If snakemake stopped unexpectedly (e.g., a job ran out of time, or a power outage) you'll get an error indicating the run directory is locked by a previous instance:
LockException:
Error: Directory cannot be locked. Please make sure that no other Snakemake process is trying to create the same files in the following directory:
...
If you are sure that no other instances of snakemake are running on this directory, the remaining lock was likely caused by a kill signal or a power loss. It can be removed with the --unlock argument.
If you're sure no other snakemake instance is running, unlock it first, then rerun as usual:
pixi run snakemake --snakefile workflow/Snakefile --profile workflow/profiles/slurm --unlock