Skip to content

Commit

Permalink
Merge pull request #151 from rwblair/issue147
Browse files Browse the repository at this point in the history
[WIP] Issue147
  • Loading branch information
rwblair committed Sep 15, 2016
2 parents d47cf47 + 98746a7 commit 4047f0f
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 57 deletions.
32 changes: 13 additions & 19 deletions fmriprep/interfaces/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
# @Date: 2016-06-03 09:35:13
# @Last Modified by: oesteban
# @Last Modified time: 2016-08-17 15:32:43
from lockfile import LockFile
import os
import os.path as op
from shutil import copy
import pkg_resources as pkgr
import re
from shutil import copy
import simplejson as json
import pkg_resources as pkgr
from lockfile import LockFile

from nipype import logging
from nipype.interfaces.base import (traits, isdefined, TraitedSpec, BaseInterface,
BaseInterfaceInputSpec, File, InputMultiPath, OutputMultiPath)

from fmriprep.utils.misc import collect_bids_data

LOGGER = logging.getLogger('interface')
Expand All @@ -27,10 +28,9 @@ class FileNotFoundError(IOError):


class BIDSDataGrabberInputSpec(BaseInterfaceInputSpec):
bids_root = traits.Directory(exists=True, mandatory=True,
desc='root folder of the BIDS dataset')
subject_data = traits.DictStrAny()
subject_id = traits.Str()
spec = File(exists=True, desc='grabbids specification file')


class BIDSDataGrabberOutputSpec(TraitedSpec):
out_dict = traits.Dict(desc='output data structure')
Expand All @@ -49,31 +49,25 @@ def __init__(self, **inputs):
super(BIDSDataGrabber, self).__init__(**inputs)

def _run_interface(self, runtime):
if isdefined(self.inputs.spec):
spec = self.inputs.spec
else:
spec = pkgr.resource_filename('fmriprep', 'data/bids.json')

bids_dict = collect_bids_data(
self.inputs.bids_root, self.inputs.subject_id, spec=spec)
bids_dict = self.inputs.subject_data

self._results['out_dict'] = bids_dict

self._results['t1w'] = bids_dict['t1w']
if not bids_dict['t1w']:
raise FileNotFoundError('No T1w images found for subject sub-{}, bids_root={}'.format(
self.inputs.subject_id, self.inputs.bids_root))
raise FileNotFoundError('No T1w images found for subject sub-{}'.format(
self.inputs.subject_id))

self._results['func'] = bids_dict['func']
if not bids_dict['func']:
raise FileNotFoundError('No functional images found for subject sub-{}, bids_root={}'.format(
self.inputs.subject_id, self.inputs.bids_root))
raise FileNotFoundError('No functional images found for subject sub-{}'.format(
self.inputs.subject_id))

for imtype in ['fmap', 'sbref']:
self._results[imtype] = bids_dict[imtype]
if not bids_dict[imtype]:
LOGGER.warn('No \'{}\' images found for sub-{} in BIDS dataset ({})'.format(
imtype, self.inputs.subject_id, self.inputs.bids_root))
LOGGER.warn('No \'{}\' images found for sub-{}'.format(
imtype, self.inputs.subject_id))


return runtime
Expand Down
7 changes: 3 additions & 4 deletions fmriprep/run_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def main():
from nipype.pipeline import engine as pe
from fmriprep import __version__
from fmriprep.workflows import base as fwb

from fmriprep.workflows.base import base_workflow_enumerator
parser = ArgumentParser(description='fMRI Preprocessing workflow',
formatter_class=RawTextHelpFormatter)

Expand Down Expand Up @@ -62,7 +62,7 @@ def main():
help='nipype plugin configuration file')
g_input.add_argument('-w', '--work-dir', action='store',
default=op.join(os.getcwd(), 'work'))
g_input.add_argument('-t', '--workflow-type', default='ds005', required=True,
g_input.add_argument('-t', '--workflow-type', default='ds005', required=False,
action='store', choices=['ds005', 'ds054', 'HPC', 'spiral'],
help='workflow type, a monkeypatch while it is not automatically identified')

Expand Down Expand Up @@ -150,8 +150,7 @@ def main():
logger.info('Subject list: %s', ', '.join(subject_list))

# Build main workflow and run
workflow_generator = getattr(fwb, 'wf_{}_type'.format(opts.workflow_type))
preproc_wf = workflow_generator(subject_list, settings=settings)
preproc_wf = base_workflow_enumerator(subject_list, settings=settings)
preproc_wf.base_dir = settings['work_dir']
preproc_wf.run(**plugin_settings)

Expand Down
19 changes: 11 additions & 8 deletions fmriprep/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import os
import re

from grabbit import Layout
from bids.grabbids import BIDSLayout

INPUTS_SPEC = {'fieldmaps': [], 'func': [], 't1': [], 'sbref': []}

Expand All @@ -23,6 +23,7 @@ def is_fieldmap_file(string):
is_fieldmap_file = True
return is_fieldmap_file


fieldmap_suffixes = {
'phasediff': r"phasediff[0-9]*\.nii(\.gz)?",
'magnitude': r"magnitude[0-9]*\.nii(\.gz)?",
Expand All @@ -32,15 +33,12 @@ def is_fieldmap_file(string):
}


def collect_bids_data(dataset, subject, spec=None, session=None, run=None):
def collect_bids_data(dataset, subject, session=None, run=None):
subject = str(subject)
if not subject.startswith('sub-'):
subject = 'sub-{}'.format(subject)

if spec is None:
raise RuntimeError('A spec file should be specified')
if subject.startswith('sub-'):
subject = subject[4:]

layout = Layout(dataset, config=spec)
layout = BIDSLayout(dataset)

if session:
session_list = [session]
Expand Down Expand Up @@ -75,7 +73,10 @@ def collect_bids_data(dataset, subject, spec=None, session=None, run=None):
imaging_data['t1w'] = t1_files
sbref_files = [x.filename for x in layout.get(**queries['sbref'])]
imaging_data['sbref'] = sbref_files
epi_files = [x.filename for x in layout.get(**queries['epi'])]
imaging_data['func'] = epi_files

'''
loop_on = ['session', 'run', 'acquisition', 'task']
get_kwargs = {}
Expand All @@ -95,6 +96,8 @@ def collect_bids_data(dataset, subject, spec=None, session=None, run=None):
in layout.get(**dict(dict(elem), **queries['epi']))]
if epi_files:
imaging_data['func'] += epi_files
'''

return imaging_data


Expand Down
56 changes: 37 additions & 19 deletions fmriprep/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,41 @@
@author: craigmoodie
"""

from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu
from nipype.interfaces import fsl
from nipype.interfaces import freesurfer as fs
from nipype.interfaces import io as nio

from fmriprep.interfaces import BIDSDataGrabber
from fmriprep.utils.misc import collect_bids_data
from fmriprep.workflows.anatomical import t1w_preprocessing
from fmriprep.workflows.sbref import sbref_preprocess, sbref_t1_registration
from fmriprep.workflows.fieldmap import phase_diff_and_magnitudes
from fmriprep.workflows.epi import (
epi_unwarp, epi_hmc, epi_sbref_registration,
epi_mean_t1_registration, epi_mni_transformation)

def wf_ds054_type(subject_list, name='fMRI_prep', settings=None):
def base_workflow_enumerator(subject_list, settings):
workflow = pe.Workflow(name='workflow_enumerator')
generated_list = []
for subject in subject_list:
generated_workflow = base_workflow_generator(subject, settings)
if generated_workflow:
generated_list.append(generated_workflow)
workflow.add_nodes(generated_list)

return workflow

def base_workflow_generator(subject_id, settings):
subject_data = collect_bids_data(settings['bids_root'], subject_id)
if (subject_data['t1w'] != [] and subject_data['sbref'] != []):
return wf_ds054_type(subject_data, settings, name=subject_id)
if (subject_data['t1w'] != [] and subject_data['sbref'] == []):
return wf_ds005_type(subject_data, settings, name=subject_id)
return None

def wf_ds054_type(subject_data, settings, name='fMRI_prep'):
"""
The main fmri preprocessing workflow, for the ds054-type of data:
Expand All @@ -39,12 +58,11 @@ def wf_ds054_type(subject_list, name='fMRI_prep', settings=None):

workflow = pe.Workflow(name=name)

inputnode = pe.Node(niu.IdentityInterface(fields=['subject_id']),
name='inputnode')
inputnode.iterables = [('subject_id', subject_list)]
# inputnode = pe.Node(niu.IdentityInterface(fields=['subject_id']),
# name='inputnode')
# inputnode.iterables = [('subject_id', subject_list)]

bidssrc = pe.Node(BIDSDataGrabber(bids_root=settings['bids_root']),
name='BIDSDatasource')
bidssrc = pe.Node(BIDSDataGrabber(subject_data=subject_data), name='BIDSDatasource')

# Preprocessing of T1w (includes registration to MNI)
t1w_pre = t1w_preprocessing(settings=settings)
Expand All @@ -60,6 +78,7 @@ def wf_ds054_type(subject_list, name='fMRI_prep', settings=None):

# HMC on the EPI
hmcwf = epi_hmc(settings=settings)
hmcwf.get_node('inputnode').iterables = ('epi', subject_data['func'])

# EPI to SBRef
epi2sbref = epi_sbref_registration()
Expand All @@ -68,7 +87,6 @@ def wf_ds054_type(subject_list, name='fMRI_prep', settings=None):
epiunwarp_wf = epi_unwarp(settings=settings)

workflow.connect([
(inputnode, bidssrc, [('subject_id', 'subject_id')]),
(bidssrc, t1w_pre, [('t1w', 'inputnode.t1w')]),
(bidssrc, fmap_est, [('fmap', 'inputnode.input_images')]),
(bidssrc, sbref_pre, [('sbref', 'inputnode.sbref')]),
Expand All @@ -79,19 +97,18 @@ def wf_ds054_type(subject_list, name='fMRI_prep', settings=None):
(t1w_pre, sbref_t1, [
('outputnode.t1_brain', 'inputnode.t1_brain'),
('outputnode.t1_seg', 'inputnode.t1_seg')]),
(bidssrc, hmcwf, [(('func', _first), 'inputnode.epi')]),
(sbref_pre, epi2sbref, [('outputnode.sbref_unwarped', 'inputnode.sbref_brain')]),
(hmcwf, epi2sbref, [('outputnode.epi_brain', 'inputnode.epi_brain')]),

(bidssrc, epiunwarp_wf, [(('func', _first), 'inputnode.epi')]),
(hmcwf, epiunwarp_wf, [('inputnode.epi', 'inputnode.epi')]),
(fmap_est, epiunwarp_wf, [('outputnode.fmap', 'inputnode.fmap'),
('outputnode.fmap_mask', 'inputnode.fmap_mask'),
('outputnode.fmap_ref', 'inputnode.fmap_ref')])
])
return workflow


def wf_ds005_type(subject_list, name='fMRI_prep', settings=None):
def wf_ds005_type(subject_data, settings, name='fMRI_prep'):
"""
The main fmri preprocessing workflow, for the ds005-type of data:
Expand All @@ -108,35 +125,35 @@ def wf_ds005_type(subject_list, name='fMRI_prep', settings=None):

workflow = pe.Workflow(name=name)

inputnode = pe.Node(niu.IdentityInterface(fields=['subject_id']),
name='inputnode')
inputnode.iterables = [('subject_id', subject_list)]
# inputnode = pe.Node(niu.IdentityInterface(fields=['subject_id']),
# name='inputnode')
# inputnode.iterables = [('subject_id', subject_list)]

bidssrc = pe.Node(BIDSDataGrabber(bids_root=settings['bids_root']),
bidssrc = pe.Node(BIDSDataGrabber(subject_data=subject_data),
name='BIDSDatasource')

# Preprocessing of T1w (includes registration to MNI)
t1w_pre = t1w_preprocessing(settings=settings)

# HMC on the EPI
hmcwf = epi_hmc(settings=settings)
hmcwf.get_node('inputnode').iterables = ('epi', subject_data['func'])

# mean EPI registration to T1w
epi_2_t1 = epi_mean_t1_registration(settings=settings)

# Apply transforms in 1 shot
epi_mni_trans_wf = epi_mni_transformation(settings=settings)


workflow.connect([
(inputnode, bidssrc, [('subject_id', 'subject_id')]),
(bidssrc, t1w_pre, [('t1w', 'inputnode.t1w')]),
(bidssrc, hmcwf, [(('func', _first), 'inputnode.epi')]),
(bidssrc, epi_2_t1, [(('func', _first), 'inputnode.epi')]),
(hmcwf, epi_2_t1, [('inputnode.epi', 'inputnode.epi')]),

(hmcwf, epi_2_t1, [('outputnode.epi_mean', 'inputnode.epi_mean')]),
(t1w_pre, epi_2_t1, [('outputnode.t1_brain', 'inputnode.t1_brain'),
('outputnode.t1_seg', 'inputnode.t1_seg')]),
(bidssrc, epi_mni_trans_wf, [(('func', _first), 'inputnode.epi')]),
(hmcwf, epi_mni_trans_wf, [('inputnode.epi', 'inputnode.epi')]),
(epi_2_t1, epi_mni_trans_wf, [('outputnode.mat_epi_to_t1', 'inputnode.mat_epi_to_t1')]),
(hmcwf, epi_mni_trans_wf, [('outputnode.xforms', 'inputnode.hmc_xforms'),
('outputnode.epi_mask', 'inputnode.epi_mask')]),
Expand All @@ -145,6 +162,7 @@ def wf_ds005_type(subject_list, name='fMRI_prep', settings=None):
'inputnode.t1_2_mni_forward_transform')])

])

return workflow

def _first(inlist):
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
-e git+https://github.com/nipy/nipype.git@master#egg=nipype
-e git+https://github.com/incf/pybids.git@master#egg=pybids
numpy
lockfile
future
Expand All @@ -8,4 +9,3 @@ nilearn
sklearn
nibabel
niworkflows>=0.0.3a3
grabbit
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def main():
# Read vars from info file
module_file =os.path.join(this_path, 'fmriprep', 'info.py')
with open(module_file) as fvars:
exec(compile(fvars.read(), module_file, 'exec'))
exec(compile(fvars.read(), module_file, 'exec'))

REQ_LINKS = []
with open('requirements.txt', 'r') as rfile:
Expand Down
7 changes: 2 additions & 5 deletions test/utils/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@ def setUp(cls):

cls.imaging_data = {
cls.subject_id: misc.collect_bids_data(os.path.join(cls.fake_ds_location),
cls.subject_id,
spec=pkgr.resource_filename(
'fmriprep',
'data/bids.json'))
cls.subject_id)
}

def test_collect_bids_data(self):
Expand Down Expand Up @@ -72,5 +69,5 @@ def assert_fieldmap_files_exist(self, pattern, key):
def assert_key_exists(self, template, key):
for subject in self.imaging_data:
self.assertIn(template.format(subject=subject),
self.imaging_data[subject][key])
'\n'.join(self.imaging_data[subject][key]))

0 comments on commit 4047f0f

Please sign in to comment.