This runs Freesurfer recon-all on all subjects and computes the BEM surfaces later used for forward modeling. BEM extraction is done using flash MRI data.
Make sure that Freesurfer is properly configured before running this script. See the Setup & Configuration section of the Freesurfer manual.
Note
Because of how long the reconstruction takes, this script is set up to only regenerate data if necessary. If you want to re-run specific steps, then you must delete the resulting files.
import os
import os.path as op
import glob
import shutil
import subprocess
import time
import numpy as np
import mne
from mne.parallel import parallel_func
import nibabel as nib
from library.config import study_path, subjects_dir, N_JOBS, spacing
def tee_output(command, log_file):
print('Running :\n%s' % " ".join(command))
with open(log_file, 'wb') as fid:
proc = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in proc.stdout:
# print(line.decode('utf-8'))
fid.write(line)
if proc.wait() != 0:
raise RuntimeError('Command failed')
def process_subject_anat(subject_id, force_recon_all=False):
subject = "sub%03d" % subject_id
print("Processing %s" % subject)
t1_fname = op.join(study_path, 'ds117', subject, 'anatomy',
'highres001.nii.gz')
log_fname = op.join(study_path, 'ds117', subject, 'my-recon-all.txt')
subject_dir = op.join(subjects_dir, subject)
if op.isdir(subject_dir):
print(' Skipping reconstruction (folder exists)')
else:
print(' Running reconstruction (usually takes hours)')
t0 = time.time()
tee_output(
['recon-all', '-all', '-s', subject, '-sd', subjects_dir,
'-i', t1_fname], log_fname)
print(' Recon for %s complete in %0.1f hours'
% (subject_id, (time.time() - t0) / 60. / 60.))
# Move flash data
fnames = glob.glob(op.join(study_path, 'ds117', subject, 'anatomy',
'FLASH', 'meflash*'))
dst_flash = op.join(subjects_dir, subject, 'mri', 'flash')
if not op.isdir(dst_flash):
print(' Copying FLASH files')
os.makedirs(dst_flash)
for f_src in fnames:
f_dst = op.basename(f_src).replace("meflash_", "mef")
f_dst = op.join(dst_flash, f_dst)
shutil.copy(f_src, f_dst)
# Fix the headers for subject 19
if subject_id == 19:
print(' Fixing FLASH files for %s' % (subject,))
fnames = (['mef05_%d.mgz' % x for x in range(7)] +
['mef30_%d.mgz' % x for x in range(7)])
for fname in fnames:
dest_fname = op.join(dst_flash, fname)
dest_img = nib.load(op.splitext(dest_fname)[0] + '.nii.gz')
# Copy the headers from subjects 1
src_img = nib.load(op.join(
subjects_dir, "sub001", "mri", "flash", fname))
hdr = src_img.header
fixed = nib.MGHImage(dest_img.get_data(), dest_img.affine, hdr)
nib.save(fixed, dest_fname)
# Make BEMs
if not op.isfile("%s/%s/mri/flash/parameter_maps/flash5.mgz"
% (subjects_dir, subject)):
print(' Converting flash MRIs')
mne.bem.convert_flash_mris(subject, convert=False,
subjects_dir=subjects_dir, verbose=False)
if not op.isfile("%s/%s/bem/flash/outer_skin.surf"
% (subjects_dir, subject)):
print(' Making BEM')
mne.bem.make_flash_bem(subject, subjects_dir=subjects_dir,
show=False, verbose=False)
for n_layers in (1, 3):
extra = '-'.join(['5120'] * n_layers)
fname_bem_surfaces = op.join(subjects_dir, subject, 'bem',
'%s-%s-bem.fif' % (subject, extra))
if not op.isfile(fname_bem_surfaces):
print(' Setting up %d-layer BEM' % (n_layers,))
conductivity = (0.3, 0.006, 0.3)[:n_layers]
try:
bem_surfaces = mne.make_bem_model(
subject, ico=4, conductivity=conductivity,
subjects_dir=subjects_dir)
except RuntimeError as exp:
print(' FAILED to create %d-layer BEM for %s: %s'
% (n_layers, subject, exp.args[0]))
continue
mne.write_bem_surfaces(fname_bem_surfaces, bem_surfaces)
fname_bem = op.join(subjects_dir, subject, 'bem',
'%s-%s-bem-sol.fif' % (subject, extra))
if not op.isfile(fname_bem):
print(' Computing %d-layer BEM solution' % (n_layers,))
bem_model = mne.read_bem_surfaces(fname_bem_surfaces)
bem = mne.make_bem_solution(bem_model)
mne.write_bem_solution(fname_bem, bem)
# Create the surface source space
fname_src = op.join(subjects_dir, subject, 'bem', '%s-%s-src.fif'
% (subject, spacing))
if not op.isfile(fname_src):
print(' Setting up source space')
src = mne.setup_source_space(subject, spacing,
subjects_dir=subjects_dir)
mne.write_source_spaces(fname_src, src)
parallel, run_func, _ = parallel_func(process_subject_anat, n_jobs=N_JOBS)
parallel(run_func(subject_id) for subject_id in range(1, 20))
# now we do something special for fsaverage
fsaverage_src_dir = op.join(os.environ['FREESURFER_HOME'], 'subjects', 'fsaverage')
fsaverage_dst_dir = op.join(subjects_dir, 'fsaverage')
print('Copying fsaverage into subjects directory') # to allow writting in folder
os.unlink(fsaverage_dst_dir) # remove symlink
shutil.copytree(fsaverage_src_dir, fsaverage_dst_dir)
fsaverage_bem = op.join(fsaverage_dst_dir, 'bem')
if not op.isdir(fsaverage_bem):
os.mkdir(fsaverage_bem)
fsaverage_src = op.join(fsaverage_bem, 'fsaverage-5-src.fif')
if not op.isfile(fsaverage_src):
print('Setting up source space for fsaverage')
src = mne.setup_source_space('fsaverage', 'ico5',
subjects_dir=subjects_dir)
for s in src:
assert np.array_equal(s['vertno'], np.arange(10242))
mne.write_source_spaces(fsaverage_src, src)
Total running time of the script: ( 0 minutes 0.000 seconds)