Guide
Get started
What QDECR needs, how to install it on Linux, macOS, Windows or a computing cluster, and a first analysis.
On this page
QDECR runs a vertex-wise analysis: the same regression model at each of the 163,842 points of FreeSurfer’s cortical surface, followed by FreeSurfer’s own correction for testing that many points at once. You write the model as an R formula, qdecr_thickness ~ age + sex, and QDECR takes care of loading the surfaces, fitting the models and finding the significant clusters.
It is for researchers who have already run their MRI scans through FreeSurfer and analyse their data in R. If that is you, this page takes you from nothing installed to a first result.
Requirements
- Linux or macOS, or Windows through WSL2. QDECR runs its parallel work in forked processes, which Windows does not have, and it calls FreeSurfer’s command-line tools.
- FreeSurfer 6.0 or later, set up so that
FREESURFER_HOMEpoints at it. QDECR callsmris_fwhmandmri_surfcluster, reads FreeSurfer’s precomputed simulations, and opens Freeview for plots. FreeSurfer needs its free licence file, which you get when you register. - Your subjects processed with
recon-all, including-qcache, which resamples each subject’s measures to thefsaveragetarget and smooths them. QDECR reads the files it writes. - R 3.6 or later: the current releases of the packages QDECR builds on need it, and they compile C++ code, so R needs a compiler too. A current R 4 release is best.
- Optional: the
magickR package, for the snapshotsqdecr_snap()makes, and a fast BLAS library.
If your subjects were processed without -qcache, run it on its own for each one:
recon-all -s sub-001 -qcacheInstall
In every case the steps are the same: FreeSurfer, then R, then QDECR. What differs is how you get the first two.
Linux
Install FreeSurfer with the official instructions and put your licence file where they say. Then make FreeSurfer part of every shell by adding two lines to ~/.bashrc, with the path where you installed it:
export FREESURFER_HOME=/usr/local/freesurfer
source "$FREESURFER_HOME/SetUpFreeSurfer.sh"Install R from your distribution or from CRAN. QDECR’s dependencies compile C++ code, so R needs its development tools too, and pak, the installer below, needs libcurl’s development files. On Debian or Ubuntu:
sudo apt install r-base r-base-dev libcurl4-openssl-devFor qdecr_snap(), add ImageMagick’s development files (libmagick++-dev on Debian and Ubuntu) and then install.packages("magick") in R.
Then install QDECR itself from GitHub, in R:
install.packages("pak")
pak::pak("slamballais/QDECR")That installs the latest release and every package it needs, which takes a few minutes the first time. To install one release in particular, name its tag: pak::pak("slamballais/QDECR@0.9.0"). If you already use remotes, remotes::install_github("slamballais/QDECR") does the same.
macOS
FreeSurfer and R both run on macOS, and so should QDECR, but we have not tested it there: if you try it, we would like to hear how it went. Install FreeSurfer with the official instructions, R from CRAN, and Apple’s command-line tools for the compiler (xcode-select --install). Then install QDECR as on Linux.
macOS has no /dev/shm, the shared memory that makes QDECR much faster on Linux. Leave dir_tmp at its default, or point it at the fastest disk you have.
Windows, through WSL2
On Windows, QDECR runs inside the Windows Subsystem for Linux: a real Ubuntu next to Windows, with its own file system and, on Windows 11, its own windows on the Windows desktop. The example analysis on this site was run this way. In PowerShell:
wsl --installAfter a restart, open Ubuntu from the Start menu. FreeSurfer, R and QDECR all go into Ubuntu, not into Windows, and the Linux steps above apply, with a few things that differ:
- Ubuntu in WSL is a minimal image. FreeSurfer’s programs, and the Qt that Freeview brings with it, need libraries it does not have. With R’s, in one go:
sudo apt install r-base r-base-dev libcurl4-openssl-dev libmagick++-dev \
libgomp1 libxt6 libsm6 libice6 libxkbcommon-x11-0 libxcb-icccm4 \
libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-shape0 \
libxcb-util1 libxcb-xinerama0 libxcb-xinput0 libxcb-xkb1- FreeSurfer’s tarball works from your home directory, unpacked with
tar -xzf, and needs nosudo; its programs find the libraries they bring along relative to themselves. PointFREESURFER_HOMEat the unpacked directory in the two~/.bashrclines above. The Ubuntu package works too, but installs into/usr/localand needs root. Either way the download is large (9.5 GB for 7.4.1) and the FreeSurfer server slow, so start it early. - Keep the data inside the Linux file system, such as in your Ubuntu home directory, rather than under
/mnt/c/: WSL reads Windows drives far more slowly. From Windows, the Linux files are at\\wsl$\Ubuntu\home\...in Explorer, which is the easy way to look at snapshots. - WSL gets half of the machine’s memory, and
/dev/shm, which Performance and memory recommends fordir_tmp, half of that. For a large study, give WSL more in%UserProfile%\.wslconfig, thenwsl --shutdown:
[wsl2]
memory=24GB- Keep WSL’s default networking. R’s worker processes talk to each other over local network connections, and WSL’s mirrored networking mode (
networkingMode=mirroredin.wslconfig) has a known fault that stalls such connections under load: an analysis withn_coresabove 1 then hangs, idle, part-way through. In NAT mode, the default, it runs through. If you need mirrored mode for other work, run QDECR withn_cores = 1. - On Windows 11, Freeview’s windows open on the Windows desktop by themselves, so
freeview()andqdecr_snap()work as they do on Linux. - An R installed on the Windows side cannot run QDECR, even pointed at the same files.
A computing cluster
On a cluster, FreeSurfer and R are usually modules and QDECR goes into your own R library. The names differ between clusters; ask module avail:
module load freesurfer RThen install QDECR once, from R on a login node, as on Linux. Run analyses as batch jobs with Rscript, and keep three things in step with what the job asked for:
n_coresshould match the cores the job was given, such asSLURM_CPUS_PER_TASKunder Slurm. QDECR only checks it against the whole machine.dir_tmpshould be on fast storage local to the node:/dev/shmif the cluster allows it, or the job’s scratch directory.- Parallel BLAS: many clusters’ R uses a multithreaded BLAS, and QDECR refuses
n_coresabove 1 alongside it. SetOPENBLAS_NUM_THREADS=1in the job script before R starts; Performance and memory explains why.
Check that it works
These checks take a minute and catch most problems before an analysis does. In R, from the environment you will run QDECR in:
library(QDECR)
Sys.getenv(c("FREESURFER_HOME", "SUBJECTS_DIR"))
Sys.which(c("mris_fwhm", "mri_surfcluster", "freeview"))Both variables should name directories, and all three programs should have a path. Then check that the fsaverage target sits in your subjects directory, and that a subject has the files -qcache writes:
ls "$SUBJECTS_DIR/fsaverage/surf/lh.inflated"
ls "$SUBJECTS_DIR/sub-001/surf/" | grep fwhm10.fsaverageThe second should list files like lh.thickness.fwhm10.fsaverage.mgh. If fsaverage is missing, which happens when the subjects were processed elsewhere, link it in from FreeSurfer:
ln -s "$FREESURFER_HOME/subjects/fsaverage" "$SUBJECTS_DIR/"Prepare the data
QDECR takes an ordinary data frame, with one row per subject:
- An ID column whose values are the names of the subjects’ directories in
SUBJECTS_DIR: the row forsub-001belongs to$SUBJECTS_DIR/sub-001. You tell QDECR its name withid. - Your variables, with categorical ones as factors, so that R codes them the way you mean. Which level is the reference decides the names of the results: with
femaleas the reference, the effect of sex is calledsexmale. - No missing values in the variables the model uses. QDECR stops rather than drop subjects without saying so. Remove incomplete rows yourself, or impute them.
pheno <- read.csv("phenotypes.csv")
pheno$sex <- factor(pheno$sex, levels = c("female", "male"))
pheno <- pheno[complete.cases(pheno[, c("id", "age", "sex")]), ]A first analysis
This fits qdecr_thickness ~ age + sex at every vertex of the left hemisphere: the effect of age on cortical thickness, adjusted for sex.
out <- qdecr_fastlm(
qdecr_thickness ~ age + sex,
data = pheno,
id = "id",
hemi = "lh",
project = "age_sex",
dir_out = "results",
dir_tmp = "/dev/shm"
)qdecr_thicknessis the vertex measure: the name of a FreeSurfer surface map withqdecr_in front.projectnames the analysis. QDECR adds the hemisphere and the measure, so the results go toresults/lh.age_sex.thickness/.dir_outmust exist or be creatable; it defaults to the working directory.dir_tmp = "/dev/shm"keeps the large temporary files in memory, which makes a big difference on Linux. Leave it out on macOS.
QDECR reports each stage as it goes: checking the input, loading the vertex data of every subject, fitting the models, estimating the smoothness of the residuals, and the cluster-wise correction. For a few hundred subjects on one core that takes minutes; Performance and memory covers larger studies.
When it finishes, out holds the result. Print it for the settings and the sample, and summarise it for the significant clusters and the regions they cover:
out
summary(out, annot = TRUE)A whole-brain study runs the right hemisphere as well, with hemi = "rh". The default cluster-wise threshold, cwp_thr = 0.025, already splits 0.05 over the two hemispheres.
From here, the quick start walks through a complete analysis of real data, with its output, and the tutorials take each part further.
What gets written to disk
Everything an analysis produces stays in its output directory, results/lh.age_sex.thickness/ above. The result in R knows the paths, so you rarely need to open these files yourself, but FreeSurfer’s tools and other software can read all of them.
For each stack, one per coefficient of the model and numbered in the order of stacks(out):
| File | What it holds |
|---|---|
stack2.coef.mgh |
The coefficient at every vertex. |
stack2.se.mgh |
Its standard error. |
stack2.t.mgh |
The t-statistic. |
stack2.p.mgh |
The p-value, as −log10(p). |
stack2.cache.th30.abs.sig.cluster.summary |
FreeSurfer’s table of the significant clusters. |
stack2.cache.th30.abs.sig.ocn.mgh |
The cluster map: each vertex numbered by its cluster. |
stack2.cache.th30.abs.sig.ocn.annot |
The same clusters as an annotation, for Freeview. |
stack2.cache.th30.abs.sig.cluster.mgh |
Each cluster’s cluster-wise p-value, as −log10(p), on its vertices. |
stack2.cache.th30.abs.sig.masked.mgh |
The p-value map, kept only inside significant clusters. |
stack2.cache.th30.abs.sig.voxel.mgh |
Vertex-wise p-values, corrected for the whole surface. |
th30 is the cluster-forming threshold: 30 stands for p < 0.001. For the analysis as a whole:
| File | What it holds |
|---|---|
lh.age_sex.thickness.rds |
The saved result, for qdecr_load(). |
stack_names.txt |
Each stack’s number and name. |
significant_clusters.txt |
The output of summary(out, annot = TRUE). |
finalMask.mgh |
The vertices the analysis covered. |
fwhm.dat |
The estimated smoothness of the residuals. |
Two arguments change this layout. With dir_out_tree = FALSE, the files go straight into dir_out rather than a directory of their own. dir_out must then be a new directory: QDECR will not write into one that exists, and refuses clobber = TRUE in this case, so that an analysis can never delete a directory it did not make. file_out_tree puts the project’s full name in front of each file, as in lh.age_sex.thickness.stack2.coef.mgh. It is on whenever dir_out_tree is off, and off otherwise, unless you set it.
While it runs, QDECR also writes large temporary files to dir_tmp: the vertex data of every subject and the residuals, about 3.3 MB per subject together, so 3.3 GB for 1,000 subjects. They are deleted at the end unless you set clean_up_bm = FALSE. Performance and memory has the details.