Пример #1
0
def analyze_openfmri_dataset(data_dir, subject=None, model_id=None,
                             task_id=None, output_dir=None, subj_prefix='*'):
    """Analyzes an open fmri dataset

    Parameters
    ----------

    data_dir : str
        Path to the base data directory

    work_dir : str
        Nipype working directory (defaults to cwd)
    """

    """
    Load nipype workflows
    """

    preproc = create_featreg_preproc(whichvol='first')
    modelfit = create_modelfit_workflow()
    fixed_fx = create_fixed_effects_flow()
    registration = create_reg_workflow()

    """
    Remove the plotting connection so that plot iterables don't propagate
    to the model stage
    """

    preproc.disconnect(preproc.get_node('plot_motion'), 'out_file',
                       preproc.get_node('outputspec'), 'motion_plots')

    """
    Set up openfmri data specific components
    """

    subjects = sorted([path.split(os.path.sep)[-1] for path in
                       glob(os.path.join(data_dir, subj_prefix))])

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id',
                                                       'model_id',
                                                       'task_id']),
                         name='infosource')
    if len(subject) == 0:
        infosource.iterables = [('subject_id', subjects),
                                ('model_id', [model_id]),
                                ('task_id', task_id)]
    else:
        infosource.iterables = [('subject_id',
                                 [subjects[subjects.index(subj)] for subj in subject]),
                                ('model_id', [model_id]),
                                ('task_id', task_id)]

    subjinfo = pe.Node(niu.Function(input_names=['subject_id', 'base_dir',
                                                 'task_id', 'model_id'],
                                    output_names=['run_id', 'conds', 'TR'],
                                    function=get_subjectinfo),
                       name='subjectinfo')
    subjinfo.inputs.base_dir = data_dir

    """
    Return data components as anat, bold and behav
    """

    datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run_id',
                                                   'task_id', 'model_id'],
                                         outfields=['anat', 'bold', 'behav',
                                                    'contrasts']),
                         name='datasource')
    datasource.inputs.base_directory = data_dir
    datasource.inputs.template = '*'
    datasource.inputs.field_template = {'anat': '%s/anatomy/T1_001.nii.gz',
                                'bold': '%s/BOLD/task%03d_r*/bold.nii.gz',
                                'behav': ('%s/model/model%03d/onsets/task%03d_'
                                          'run%03d/cond*.txt'),
                                'contrasts': ('models/model%03d/'
                                              'task_contrasts.txt')}
    datasource.inputs.template_args = {'anat': [['subject_id']],
                                       'bold': [['subject_id', 'task_id']],
                                       'behav': [['subject_id', 'model_id',
                                                  'task_id', 'run_id']],
                                       'contrasts': [['model_id']]}
    datasource.inputs.sort_filelist = True

    """
    Create meta workflow
    """

    wf = pe.Workflow(name='openfmri')
    wf.connect(infosource, 'subject_id', subjinfo, 'subject_id')
    wf.connect(infosource, 'model_id', subjinfo, 'model_id')
    wf.connect(infosource, 'task_id', subjinfo, 'task_id')
    wf.connect(infosource, 'subject_id', datasource, 'subject_id')
    wf.connect(infosource, 'model_id', datasource, 'model_id')
    wf.connect(infosource, 'task_id', datasource, 'task_id')
    wf.connect(subjinfo, 'run_id', datasource, 'run_id')
    wf.connect([(datasource, preproc, [('bold', 'inputspec.func')]),
                ])

    def get_highpass(TR, hpcutoff):
        return hpcutoff / (2 * TR)
    gethighpass = pe.Node(niu.Function(input_names=['TR', 'hpcutoff'],
                                       output_names=['highpass'],
                                       function=get_highpass),
                          name='gethighpass')
    wf.connect(subjinfo, 'TR', gethighpass, 'TR')
    wf.connect(gethighpass, 'highpass', preproc, 'inputspec.highpass')

    """
    Setup a basic set of contrasts, a t-test per condition
    """

    def get_contrasts(contrast_file, task_id, conds):
        import numpy as np
        contrast_def = np.genfromtxt(contrast_file, dtype=object)
        if len(contrast_def.shape) == 1:
            contrast_def = contrast_def[None, :]
        contrasts = []
        for row in contrast_def:
            if row[0] != 'task%03d' % task_id:
                continue
            con = [row[1], 'T', ['cond%03d' % (i + 1)  for i in range(len(conds))],
                   row[2:].astype(float).tolist()]
            contrasts.append(con)
        # add auto contrasts for each column
        for i, cond in enumerate(conds):
            con = [cond, 'T', ['cond%03d' % (i + 1)], [1]]
            contrasts.append(con)
        return contrasts

    contrastgen = pe.Node(niu.Function(input_names=['contrast_file',
                                                    'task_id', 'conds'],
                                       output_names=['contrasts'],
                                       function=get_contrasts),
                          name='contrastgen')

    art = pe.MapNode(interface=ra.ArtifactDetect(use_differences=[True, False],
                                                 use_norm=True,
                                                 norm_threshold=1,
                                                 zintensity_threshold=3,
                                                 parameter_source='FSL',
                                                 mask_type='file'),
                     iterfield=['realigned_files', 'realignment_parameters',
                                'mask_file'],
                     name="art")

    modelspec = pe.Node(interface=model.SpecifyModel(),
                           name="modelspec")
    modelspec.inputs.input_units = 'secs'

    def check_behav_list(behav):
        out_behav = []
        if isinstance(behav, six.string_types):
            behav = [behav]
        for val in behav:
            if not isinstance(val, list):
                out_behav.append([val])
            else:
                out_behav.append(val)
        return out_behav

    wf.connect(subjinfo, 'TR', modelspec, 'time_repetition')
    wf.connect(datasource, ('behav', check_behav_list), modelspec, 'event_files')
    wf.connect(subjinfo, 'TR', modelfit, 'inputspec.interscan_interval')
    wf.connect(subjinfo, 'conds', contrastgen, 'conds')
    wf.connect(datasource, 'contrasts', contrastgen, 'contrast_file')
    wf.connect(infosource, 'task_id', contrastgen, 'task_id')
    wf.connect(contrastgen, 'contrasts', modelfit, 'inputspec.contrasts')

    wf.connect([(preproc, art, [('outputspec.motion_parameters',
                                 'realignment_parameters'),
                                ('outputspec.realigned_files',
                                 'realigned_files'),
                                ('outputspec.mask', 'mask_file')]),
                (preproc, modelspec, [('outputspec.highpassed_files',
                                       'functional_runs'),
                                      ('outputspec.motion_parameters',
                                       'realignment_parameters')]),
                (art, modelspec, [('outlier_files', 'outlier_files')]),
                (modelspec, modelfit, [('session_info',
                                        'inputspec.session_info')]),
                (preproc, modelfit, [('outputspec.highpassed_files',
                                      'inputspec.functional_data')])
                ])

    """
    Reorder the copes so that now it combines across runs
    """

    def sort_copes(files):
        numelements = len(files[0])
        outfiles = []
        for i in range(numelements):
            outfiles.insert(i, [])
            for j, elements in enumerate(files):
                outfiles[i].append(elements[i])
        return outfiles

    def num_copes(files):
        return len(files)

    pickfirst = lambda x: x[0]

    wf.connect([(preproc, fixed_fx, [(('outputspec.mask', pickfirst),
                                      'flameo.mask_file')]),
                (modelfit, fixed_fx, [(('outputspec.copes', sort_copes),
                                       'inputspec.copes'),
                                       ('outputspec.dof_file',
                                        'inputspec.dof_files'),
                                       (('outputspec.varcopes',
                                         sort_copes),
                                        'inputspec.varcopes'),
                                       (('outputspec.copes', num_copes),
                                        'l2model.num_copes'),
                                       ])
                ])

    wf.connect(preproc, 'outputspec.mean', registration, 'inputspec.mean_image')
    wf.connect(datasource, 'anat', registration, 'inputspec.anatomical_image')
    registration.inputs.inputspec.target_image = fsl.Info.standard_image('MNI152_T1_2mm.nii.gz')
    registration.inputs.inputspec.target_image_brain = fsl.Info.standard_image('MNI152_T1_2mm_brain.nii.gz')
    registration.inputs.inputspec.config_file = 'T1_2_MNI152_2mm'

    def merge_files(copes, varcopes, zstats):
        out_files = []
        splits = []
        out_files.extend(copes)
        splits.append(len(copes))
        out_files.extend(varcopes)
        splits.append(len(varcopes))
        out_files.extend(zstats)
        splits.append(len(zstats))
        return out_files, splits

    mergefunc = pe.Node(niu.Function(input_names=['copes', 'varcopes',
                                                  'zstats'],
                                   output_names=['out_files', 'splits'],
                                   function=merge_files),
                      name='merge_files')
    wf.connect([(fixed_fx.get_node('outputspec'), mergefunc,
                                 [('copes', 'copes'),
                                  ('varcopes', 'varcopes'),
                                  ('zstats', 'zstats'),
                                  ])])
    wf.connect(mergefunc, 'out_files', registration, 'inputspec.source_files')

    def split_files(in_files, splits):
        copes = in_files[:splits[0]]
        varcopes = in_files[splits[0]:(splits[0] + splits[1])]
        zstats = in_files[(splits[0] + splits[1]):]
        return copes, varcopes, zstats

    splitfunc = pe.Node(niu.Function(input_names=['in_files', 'splits'],
                                     output_names=['copes', 'varcopes',
                                                   'zstats'],
                                     function=split_files),
                      name='split_files')
    wf.connect(mergefunc, 'splits', splitfunc, 'splits')
    wf.connect(registration, 'outputspec.transformed_files',
               splitfunc, 'in_files')


    """
    Connect to a datasink
    """

    def get_subs(subject_id, conds, model_id, task_id):
        subs = [('_subject_id_%s_' % subject_id, '')]
        subs.append(('_model_id_%d' % model_id, 'model%03d' %model_id))
        subs.append(('task_id_%d/' % task_id, '/task%03d_' % task_id))
        subs.append(('bold_dtype_mcf_mask_smooth_mask_gms_tempfilt_mean_warp',
        'mean'))
        subs.append(('bold_dtype_mcf_mask_smooth_mask_gms_tempfilt_mean_flirt',
        'affine'))

        for i in range(len(conds)):
            subs.append(('_flameo%d/cope1.' % i, 'cope%02d.' % (i + 1)))
            subs.append(('_flameo%d/varcope1.' % i, 'varcope%02d.' % (i + 1)))
            subs.append(('_flameo%d/zstat1.' % i, 'zstat%02d.' % (i + 1)))
            subs.append(('_flameo%d/tstat1.' % i, 'tstat%02d.' % (i + 1)))
            subs.append(('_flameo%d/res4d.' % i, 'res4d%02d.' % (i + 1)))
            subs.append(('_warpall%d/cope1_warp.' % i,
                         'cope%02d.' % (i + 1)))
            subs.append(('_warpall%d/varcope1_warp.' % (len(conds) + i),
                         'varcope%02d.' % (i + 1)))
            subs.append(('_warpall%d/zstat1_warp.' % (2 * len(conds) + i),
                         'zstat%02d.' % (i + 1)))
        return subs

    subsgen = pe.Node(niu.Function(input_names=['subject_id', 'conds',
                                                'model_id', 'task_id'],
                                   output_names=['substitutions'],
                                   function=get_subs),
                      name='subsgen')

    datasink = pe.Node(interface=nio.DataSink(),
                       name="datasink")
    wf.connect(infosource, 'subject_id', datasink, 'container')
    wf.connect(infosource, 'subject_id', subsgen, 'subject_id')
    wf.connect(infosource, 'model_id', subsgen, 'model_id')
    wf.connect(infosource, 'task_id', subsgen, 'task_id')
    wf.connect(contrastgen, 'contrasts', subsgen, 'conds')
    wf.connect(subsgen, 'substitutions', datasink, 'substitutions')
    wf.connect([(fixed_fx.get_node('outputspec'), datasink,
                                 [('res4d', 'res4d'),
                                  ('copes', 'copes'),
                                  ('varcopes', 'varcopes'),
                                  ('zstats', 'zstats'),
                                  ('tstats', 'tstats')])
                                 ])
    wf.connect([(splitfunc, datasink,
                 [('copes', 'copes.mni'),
                  ('varcopes', 'varcopes.mni'),
                  ('zstats', 'zstats.mni'),
                  ])])
    wf.connect(registration, 'outputspec.transformed_mean', datasink, 'mean.mni')
    wf.connect(registration, 'outputspec.func2anat_transform', datasink, 'xfm.mean2anat')
    wf.connect(registration, 'outputspec.anat2target_transform', datasink, 'xfm.anat2target')

    """
    Set processing parameters
    """

    hpcutoff = 120.
    preproc.inputs.inputspec.fwhm = 6.0
    gethighpass.inputs.hpcutoff = hpcutoff
    modelspec.inputs.high_pass_filter_cutoff = hpcutoff
    modelfit.inputs.inputspec.bases = {'dgamma': {'derivs': True}}
    modelfit.inputs.inputspec.model_serial_correlations = True
    modelfit.inputs.inputspec.film_threshold = 1000

    datasink.inputs.base_directory = output_dir
    return wf
Пример #2
0
                                amplitudes=None,
                                tmod=None,
                                pmod=None,
                                regressor_names=None,
                                regressors=None)]

modelfit = create_modelfit_workflow(f_contrasts=True)
modelfit.inputs.inputspec.interscan_interval = TR
modelfit.inputs.inputspec.model_serial_correlations = True
modelfit.inputs.inputspec.bases = {'dgamma': {'derivs': True}}
cont1 = ['Visual>Baseline','T', ['Visual','Auditory'],[1,0]]
cont2 = ['Auditory>Baseline','T', ['Visual','Auditory'],[0,1]]
cont3 = ['Task','F', [cont1, cont2]]
modelfit.inputs.inputspec.contrasts = [cont1,cont2,cont3]

registration = create_reg_workflow()
registration.inputs.inputspec.target_image = fsl.Info.standard_image('MNI152_T1_2mm.nii.gz')
registration.inputs.inputspec.target_image_brain = fsl.Info.standard_image('MNI152_T1_2mm_brain.nii.gz')
registration.inputs.inputspec.config_file = 'T1_2_MNI152_2mm'

"""
Set up complete workflow
========================
"""

l1pipeline = pe.Workflow(name= "level1")
l1pipeline.base_dir = os.path.abspath('./fsl_feeds/workingdir')
l1pipeline.config = {"execution": {"crashdump_dir":os.path.abspath('./fsl_feeds/crashdumps')}}

l1pipeline.connect(datasource, 'func', preproc,'inputspec.func')
l1pipeline.connect(preproc, 'outputspec.highpassed_files', modelspec, 'functional_runs')
Пример #3
0
          tmod=None,
          pmod=None,
          regressor_names=None,
          regressors=None)
]

modelfit = create_modelfit_workflow(f_contrasts=True)
modelfit.inputs.inputspec.interscan_interval = TR
modelfit.inputs.inputspec.model_serial_correlations = True
modelfit.inputs.inputspec.bases = {'dgamma': {'derivs': True}}
cont1 = ['Visual>Baseline', 'T', ['Visual', 'Auditory'], [1, 0]]
cont2 = ['Auditory>Baseline', 'T', ['Visual', 'Auditory'], [0, 1]]
cont3 = ['Task', 'F', [cont1, cont2]]
modelfit.inputs.inputspec.contrasts = [cont1, cont2, cont3]

registration = create_reg_workflow()
registration.inputs.inputspec.target_image = fsl.Info.standard_image(
    'MNI152_T1_2mm.nii.gz')
registration.inputs.inputspec.target_image_brain = fsl.Info.standard_image(
    'MNI152_T1_2mm_brain.nii.gz')
registration.inputs.inputspec.config_file = 'T1_2_MNI152_2mm'
"""
Set up complete workflow
========================
"""

l1pipeline = pe.Workflow(name="level1")
l1pipeline.base_dir = os.path.abspath('./fsl_feeds/workingdir')
l1pipeline.config = {
    "execution": {
        "crashdump_dir": os.path.abspath('./fsl_feeds/crashdumps')
Пример #4
0
def create_indnet_workflow(hp_cutoff=100,
                           smoothing=5,
                           smm_threshold=0.5,
                           binarise_threshold=0.5,
                           melodic_seed=None,
                           aggr_aroma=False,
                           name="indnet"):

    indnet = Workflow(name=name)

    # Input node
    inputspec = Node(utility.IdentityInterface(
        fields=['anat_file', 'func_file', 'templates', 'networks']),
                     name='inputspec')

    # T1 skullstrip
    anat_bet = Node(fsl.BET(), name="anat_bet")

    # EPI preprocessing
    func_realignsmooth = create_featreg_preproc(highpass=False,
                                                whichvol='first',
                                                name='func_realignsmooth')
    func_realignsmooth.inputs.inputspec.fwhm = smoothing

    # Transform EPI to MNI space
    func_2mni = create_reg_workflow(name='func_2mni')
    func_2mni.inputs.inputspec.target_image = fsl.Info.standard_image(
        'MNI152_T1_2mm.nii.gz')
    func_2mni.inputs.inputspec.target_image_brain = fsl.Info.standard_image(
        'MNI152_T1_2mm_brain.nii.gz')
    func_2mni.inputs.inputspec.config_file = 'T1_2_MNI152_2mm'

    # Segmentation of T1
    anat_segmentation = Node(fsl.FAST(output_biascorrected=True),
                             name='anat_segmentation')

    # Transfrom segments to EPI space
    segments_2func = create_segments_2func_workflow(
        threshold=binarise_threshold, name='segments_2func')

    # Transform templates to EPI space
    templates_2func = create_templates_2func_workflow(
        threshold=binarise_threshold, name='templates_2func')

    # Mask network templates with GM
    gm_mask_templates = MapNode(fsl.ImageMaths(op_string='-mul'),
                                iterfield=['in_file2'],
                                name='gm_mask_templates')

    # Mask for ICA-AROMA and statistics
    func_brainmask = Node(fsl.BET(frac=0.3,
                                  mask=True,
                                  no_output=True,
                                  robust=True),
                          name='func_brainmask')

    # Melodic ICA
    if melodic_seed != None:
        func_melodic = Node(fsl.MELODIC(args='--seed={}'.format(melodic_seed),
                                        out_stats=True),
                            name='func_melodic')

    # ICA-AROMA
    func_aroma = Node(fsl.ICA_AROMA(), name='func_aroma')
    if aggr_aroma:
        func_aroma.inputs.denoise_type = 'aggr'

    else:
        func_aroma.inputs.denoise_type = 'nonaggr'

    # Highpass filter ICA results
    func_highpass = create_highpass_filter(cutoff=hp_cutoff,
                                           name='func_highpass')

    # Calculate mean CSF sgnal
    csf_meansignal = Node(fsl.ImageMeants(), name='csf_meansignal')

    # Calculate mean WM signal
    wm_meansignal = Node(fsl.ImageMeants(), name='wm_meansignal')

    # Calculate mean non-brain signal
    nonbrain_meansignal = create_nonbrain_meansignal(
        name='nonbrain_meansignal')

    # Calculate first Eigenvariates
    firsteigenvariates = MapNode(fsl.ImageMeants(show_all=True, eig=True),
                                 iterfield=['mask'],
                                 name='firsteigenvariates')

    # Combine first eigenvariates and wm/csf/non-brain signals
    regressors = Node(utility.Merge(4), name='regressors')

    # z-transform regressors
    ztransform = MapNode(Ztransform(),
                         iterfield=['in_file'],
                         name='ztransform')

    # Create design matrix
    designmatrix = Node(DesignMatrix(), name='designmatrix')

    # Create contrasts
    contrasts = Node(Contrasts(), name='contrasts')

    # GLM
    glm = Node(fsl.GLM(), name='glm')
    glm.inputs.out_z_name = 'z_stats.nii.gz'
    glm.inputs.demean = True

    # Split z-maps
    zmaps = Node(fsl.Split(), name='zmaps')
    zmaps.inputs.dimension = 't'

    # Spatial Mixture Modelling
    smm = MapNode(fsl.SMM(), iterfield=['spatial_data_file'], name='smm')

    # Transform probability maps to native (anat) space
    actmaps_2anat = MapNode(fsl.ApplyXFM(),
                            iterfield=['in_file'],
                            name='actmaps_2anat')

    # Transform probability maps to MNI space
    actmaps_2mni = MapNode(fsl.ApplyWarp(),
                           iterfield=['in_file'],
                           name='actmaps_2mni')
    actmaps_2mni.inputs.ref_file = fsl.Info.standard_image(
        'MNI152_T1_2mm.nii.gz')

    # Create network masks in native (func) space
    network_masks_func = create_network_masks_workflow(
        name='network_masks_func', smm_threshold=smm_threshold)

    # Create network masks in native (anat) space
    network_masks_anat = create_network_masks_workflow(
        name='network_masks_anat', smm_threshold=smm_threshold)

    # Create network masks in MNI space
    network_masks_mni = create_network_masks_workflow(
        name='network_masks_mni', smm_threshold=smm_threshold)

    # Output node
    outputspec = Node(utility.IdentityInterface(fields=[
        'network_masks_func_main', 'network_masks_func_exclusive',
        'network_masks_anat_main', 'network_masks_anat_exclusive',
        'network_masks_mni_main', 'network_masks_mni_exclusive',
        'preprocessed_func_file', 'preprocessed_anat_file',
        'motion_parameters', 'func2anat_transform', 'anat2mni_transform'
    ]),
                      name='outputspec')

    # Helper functions
    def get_first_item(x):
        try:
            return x[0]
        except:
            return x

    def get_second_item(x):
        return x[1]

    def get_third_item(x):
        return x[2]

    def get_components(x):
        return [y['components'] for y in x]

    # Connect the nodes

    # anat_bet
    indnet.connect(inputspec, 'anat_file', anat_bet, 'in_file')

    # func_realignsmooth
    indnet.connect(inputspec, 'func_file', func_realignsmooth,
                   'inputspec.func')

    # func_2mni
    indnet.connect(func_realignsmooth,
                   ('outputspec.smoothed_files', get_first_item), func_2mni,
                   'inputspec.source_files')
    indnet.connect(inputspec, 'anat_file', func_2mni,
                   'inputspec.anatomical_image')
    indnet.connect(func_realignsmooth, 'outputspec.reference', func_2mni,
                   'inputspec.mean_image')

    # anat_segmentation
    indnet.connect(anat_bet, 'out_file', anat_segmentation, 'in_files')

    # segments_2func
    indnet.connect(anat_segmentation, 'partial_volume_files', segments_2func,
                   'inputspec.segments')
    indnet.connect(func_2mni, 'outputspec.func2anat_transform', segments_2func,
                   'inputspec.premat')
    indnet.connect(func_realignsmooth, 'outputspec.mean', segments_2func,
                   'inputspec.func_file')

    # templates_2func
    indnet.connect(func_realignsmooth, 'outputspec.mean', templates_2func,
                   'inputspec.func_file')
    indnet.connect(func_2mni, 'outputspec.func2anat_transform',
                   templates_2func, 'inputspec.premat')
    indnet.connect(func_2mni, 'outputspec.anat2target_transform',
                   templates_2func, 'inputspec.warp')
    indnet.connect(inputspec, 'templates', templates_2func,
                   'inputspec.templates')

    # gm_mask_templates
    indnet.connect(segments_2func,
                   ('outputspec.segments_2func_files', get_second_item),
                   gm_mask_templates, 'in_file')
    indnet.connect(templates_2func, 'outputspec.templates_2func_files',
                   gm_mask_templates, 'in_file2')

    # func_brainmask
    indnet.connect(func_realignsmooth, 'outputspec.mean', func_brainmask,
                   'in_file')

    # func_melodic
    if melodic_seed != None:
        indnet.connect(func_realignsmooth,
                       ('outputspec.smoothed_files', get_first_item),
                       func_melodic, 'in_files')
        indnet.connect(func_brainmask, 'mask_file', func_melodic, 'mask')

    # func_aroma
    indnet.connect(func_realignsmooth,
                   ('outputspec.smoothed_files', get_first_item), func_aroma,
                   'in_file')
    indnet.connect(func_2mni, 'outputspec.func2anat_transform', func_aroma,
                   'mat_file')
    indnet.connect(func_2mni, 'outputspec.anat2target_transform', func_aroma,
                   'fnirt_warp_file')
    indnet.connect(func_realignsmooth,
                   ('outputspec.motion_parameters', get_first_item),
                   func_aroma, 'motion_parameters')
    indnet.connect(func_brainmask, 'mask_file', func_aroma, 'mask')
    if melodic_seed != None:
        indnet.connect(func_melodic, 'out_dir', func_aroma, 'melodic_dir')

    # func_highpass
    if aggr_aroma:
        indnet.connect(func_aroma, 'aggr_denoised_file', func_highpass,
                       'inputspec.in_file')
    else:
        indnet.connect(func_aroma, 'nonaggr_denoised_file', func_highpass,
                       'inputspec.in_file')

    # csf_meansignal
    indnet.connect(segments_2func,
                   ('outputspec.segments_2func_files', get_first_item),
                   csf_meansignal, 'mask')
    indnet.connect(func_highpass, 'outputspec.filtered_file', csf_meansignal,
                   'in_file')

    # wm_meansignal
    indnet.connect(segments_2func,
                   ('outputspec.segments_2func_files', get_third_item),
                   wm_meansignal, 'mask')
    indnet.connect(func_highpass, 'outputspec.filtered_file', wm_meansignal,
                   'in_file')

    # nonbrain_meansignal
    indnet.connect(inputspec, 'func_file', nonbrain_meansignal,
                   'inputspec.func_file')

    # firsteigenvariates
    indnet.connect(gm_mask_templates, 'out_file', firsteigenvariates, 'mask')
    indnet.connect(func_highpass, 'outputspec.filtered_file',
                   firsteigenvariates, 'in_file')

    # regressors
    indnet.connect(firsteigenvariates, 'out_file', regressors, 'in1')
    indnet.connect(wm_meansignal, 'out_file', regressors, 'in2')
    indnet.connect(csf_meansignal, 'out_file', regressors, 'in3')
    indnet.connect(nonbrain_meansignal, 'outputspec.nonbrain_regressor',
                   regressors, 'in4')

    # ztransform
    indnet.connect(regressors, 'out', ztransform, 'in_file')

    # designmatrix
    indnet.connect(ztransform, 'out_file', designmatrix, 'in_files')

    # contrasts
    indnet.connect(inputspec, ('networks', get_components), contrasts,
                   'in_list')
    indnet.connect(designmatrix, 'out_file', contrasts, 'design')

    # glm
    indnet.connect(designmatrix, 'out_file', glm, 'design')
    indnet.connect(contrasts, 'out_file', glm, 'contrasts')
    indnet.connect(func_brainmask, 'mask_file', glm, 'mask')
    indnet.connect(func_highpass, 'outputspec.filtered_file', glm, 'in_file')

    # zmaps
    indnet.connect(glm, 'out_z', zmaps, 'in_file')

    # smm
    indnet.connect(zmaps, 'out_files', smm, 'spatial_data_file')
    indnet.connect(func_brainmask, 'mask_file', smm, 'mask')

    # actmaps_2anat
    indnet.connect(smm, 'activation_p_map', actmaps_2anat, 'in_file')
    indnet.connect(func_2mni, 'outputspec.func2anat_transform', actmaps_2anat,
                   'in_matrix_file')
    indnet.connect(anat_bet, 'out_file', actmaps_2anat, 'reference')

    # actmaps_2mni
    indnet.connect(smm, 'activation_p_map', actmaps_2mni, 'in_file')
    indnet.connect(templates_2func, 'outputspec.func_2mni_warp', actmaps_2mni,
                   'field_file')

    # network_masks_func
    indnet.connect(smm, 'activation_p_map', network_masks_func,
                   'inputspec.actmaps')
    indnet.connect(inputspec, 'networks', network_masks_func,
                   'inputspec.networks')

    # network_masks_anat
    indnet.connect(actmaps_2anat, 'out_file', network_masks_anat,
                   'inputspec.actmaps')
    indnet.connect(inputspec, 'networks', network_masks_anat,
                   'inputspec.networks')

    # network_masks_mni
    indnet.connect(actmaps_2mni, 'out_file', network_masks_mni,
                   'inputspec.actmaps')
    indnet.connect(inputspec, 'networks', network_masks_mni,
                   'inputspec.networks')

    # output node
    indnet.connect(network_masks_func, 'outputspec.main_masks', outputspec,
                   'network_masks_func_main')
    indnet.connect(network_masks_func, 'outputspec.exclusive_masks',
                   outputspec, 'network_masks_func_exclusive')
    indnet.connect(network_masks_anat, 'outputspec.main_masks', outputspec,
                   'network_masks_anat_main')
    indnet.connect(network_masks_anat, 'outputspec.exclusive_masks',
                   outputspec, 'network_masks_anat_exclusive')
    indnet.connect(network_masks_mni, 'outputspec.main_masks', outputspec,
                   'network_masks_mni_main')
    indnet.connect(network_masks_mni, 'outputspec.exclusive_masks', outputspec,
                   'network_masks_mni_exclusive')
    indnet.connect(func_highpass, 'outputspec.filtered_file', outputspec,
                   'preprocessed_func_file')
    indnet.connect(anat_segmentation, 'restored_image', outputspec,
                   'preprocessed_anat_file')
    indnet.connect(func_realignsmooth,
                   ('outputspec.motion_parameters', get_first_item),
                   outputspec, 'motion_parameters')
    indnet.connect(func_2mni, 'outputspec.func2anat_transform', outputspec,
                   'func2anat_transform')
    indnet.connect(func_2mni, 'outputspec.anat2target_transform', outputspec,
                   'anat2mni_transform')

    return indnet
Пример #5
0
def analyze_openfmri_dataset(data_dir, subject=None, model_id=None,
                             task_id=None, output_dir=None):
    """Analyzes an open fmri dataset

    Parameters
    ----------

    data_dir : str
        Path to the base data directory

    work_dir : str
        Nipype working directory (defaults to cwd)
    """

    """
    Load nipype workflows
    """

    preproc = create_featreg_preproc(whichvol='first')
    modelfit = create_modelfit_workflow()
    fixed_fx = create_fixed_effects_flow()
    registration = create_reg_workflow()

    """
    Remove the plotting connection so that plot iterables don't propagate
    to the model stage
    """

    preproc.disconnect(preproc.get_node('plot_motion'), 'out_file',
                       preproc.get_node('outputspec'), 'motion_plots')

    """
    Set up openfmri data specific components
    """

    subjects = sorted([path.split(os.path.sep)[-1] for path in
                       glob(os.path.join(data_dir, 'sub*'))])

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id',
                                                       'model_id',
                                                       'task_id']),
                         name='infosource')
    if subject is None:
        infosource.iterables = [('subject_id', subjects),
                                ('model_id', [model_id]),
                                ('task_id', [task_id])]
    else:
        infosource.iterables = [('subject_id',
                                 [subjects[subjects.index(subject)]]),
                                ('model_id', [model_id]),
                                ('task_id', [task_id])]

    subjinfo = pe.Node(niu.Function(input_names=['subject_id', 'base_dir',
                                                 'task_id', 'model_id'],
                                    output_names=['run_id', 'conds', 'TR'],
                                    function=get_subjectinfo),
                       name='subjectinfo')
    subjinfo.inputs.base_dir = data_dir

    """
    Return data components as anat, bold and behav
    """

    datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run_id',
                                                   'task_id', 'model_id'],
                                         outfields=['anat', 'bold', 'behav',
                                                    'contrasts']),
                         name='datasource')
    datasource.inputs.base_directory = data_dir
    datasource.inputs.template = '*'
    datasource.inputs.field_template = {'anat': '%s/anatomy/highres001.nii.gz',
                                'bold': '%s/BOLD/task%03d_r*/bold.nii.gz',
                                'behav': ('%s/model/model%03d/onsets/task%03d_'
                                          'run%03d/cond*.txt'),
                                'contrasts': ('models/model%03d/'
                                              'task_contrasts.txt')}
    datasource.inputs.template_args = {'anat': [['subject_id']],
                                       'bold': [['subject_id', 'task_id']],
                                       'behav': [['subject_id', 'model_id',
                                                  'task_id', 'run_id']],
                                       'contrasts': [['model_id']]}
    datasource.inputs.sort_filelist = True

    """
    Create meta workflow
    """

    wf = pe.Workflow(name='openfmri')
    wf.connect(infosource, 'subject_id', subjinfo, 'subject_id')
    wf.connect(infosource, 'model_id', subjinfo, 'model_id')
    wf.connect(infosource, 'task_id', subjinfo, 'task_id')
    wf.connect(infosource, 'subject_id', datasource, 'subject_id')
    wf.connect(infosource, 'model_id', datasource, 'model_id')
    wf.connect(infosource, 'task_id', datasource, 'task_id')
    wf.connect(subjinfo, 'run_id', datasource, 'run_id')
    wf.connect([(datasource, preproc, [('bold', 'inputspec.func')]),
                ])

    def get_highpass(TR, hpcutoff):
        return hpcutoff / (2 * TR)
    gethighpass = pe.Node(niu.Function(input_names=['TR', 'hpcutoff'],
                                       output_names=['highpass'],
                                       function=get_highpass),
                          name='gethighpass')
    wf.connect(subjinfo, 'TR', gethighpass, 'TR')
    wf.connect(gethighpass, 'highpass', preproc, 'inputspec.highpass')

    """
    Setup a basic set of contrasts, a t-test per condition
    """

    def get_contrasts(contrast_file, task_id, conds):
        import numpy as np
        contrast_def = np.genfromtxt(contrast_file, dtype=object)
        if len(contrast_def.shape) == 1:
            contrast_def = contrast_def[None, :]
        contrasts = []
        for row in contrast_def:
            if row[0] != 'task%03d' % task_id:
                continue
            con = [row[1], 'T', ['cond%03d' % (i + 1)  for i in range(len(conds))],
                   row[2:].astype(float).tolist()]
            contrasts.append(con)
        # add auto contrasts for each column
        for i, cond in enumerate(conds):
            con = [cond, 'T', ['cond%03d' % (i + 1)], [1]]
            contrasts.append(con)
        return contrasts

    contrastgen = pe.Node(niu.Function(input_names=['contrast_file',
                                                    'task_id', 'conds'],
                                       output_names=['contrasts'],
                                       function=get_contrasts),
                          name='contrastgen')

    art = pe.MapNode(interface=ra.ArtifactDetect(use_differences=[True, False],
                                                 use_norm=True,
                                                 norm_threshold=1,
                                                 zintensity_threshold=3,
                                                 parameter_source='FSL',
                                                 mask_type='file'),
                     iterfield=['realigned_files', 'realignment_parameters',
                                'mask_file'],
                     name="art")

    modelspec = pe.Node(interface=model.SpecifyModel(),
                           name="modelspec")
    modelspec.inputs.input_units = 'secs'

    wf.connect(subjinfo, 'TR', modelspec, 'time_repetition')
    wf.connect(datasource, 'behav', modelspec, 'event_files')
    wf.connect(subjinfo, 'TR', modelfit, 'inputspec.interscan_interval')
    wf.connect(subjinfo, 'conds', contrastgen, 'conds')
    wf.connect(datasource, 'contrasts', contrastgen, 'contrast_file')
    wf.connect(infosource, 'task_id', contrastgen, 'task_id')
    wf.connect(contrastgen, 'contrasts', modelfit, 'inputspec.contrasts')

    wf.connect([(preproc, art, [('outputspec.motion_parameters',
                                 'realignment_parameters'),
                                ('outputspec.realigned_files',
                                 'realigned_files'),
                                ('outputspec.mask', 'mask_file')]),
                (preproc, modelspec, [('outputspec.highpassed_files',
                                       'functional_runs'),
                                      ('outputspec.motion_parameters',
                                       'realignment_parameters')]),
                (art, modelspec, [('outlier_files', 'outlier_files')]),
                (modelspec, modelfit, [('session_info',
                                        'inputspec.session_info')]),
                (preproc, modelfit, [('outputspec.highpassed_files',
                                      'inputspec.functional_data')])
                ])

    """
    Reorder the copes so that now it combines across runs
    """

    def sort_copes(files):
        numelements = len(files[0])
        outfiles = []
        for i in range(numelements):
            outfiles.insert(i, [])
            for j, elements in enumerate(files):
                outfiles[i].append(elements[i])
        return outfiles

    def num_copes(files):
        return len(files)

    pickfirst = lambda x: x[0]

    wf.connect([(preproc, fixed_fx, [(('outputspec.mask', pickfirst),
                                      'flameo.mask_file')]),
                (modelfit, fixed_fx, [(('outputspec.copes', sort_copes),
                                       'inputspec.copes'),
                                       ('outputspec.dof_file',
                                        'inputspec.dof_files'),
                                       (('outputspec.varcopes',
                                         sort_copes),
                                        'inputspec.varcopes'),
                                       (('outputspec.copes', num_copes),
                                        'l2model.num_copes'),
                                       ])
                ])

    wf.connect(preproc, 'outputspec.mean', registration, 'inputspec.mean_image')
    wf.connect(datasource, 'anat', registration, 'inputspec.anatomical_image')
    registration.inputs.inputspec.target_image = fsl.Info.standard_image('MNI152_T1_2mm.nii.gz')

    def merge_files(copes, varcopes):
        out_files = []
        splits = []
        out_files.extend(copes)
        splits.append(len(copes))
        out_files.extend(varcopes)
        splits.append(len(varcopes))
        return out_files, splits

    mergefunc = pe.Node(niu.Function(input_names=['copes', 'varcopes'],
                                   output_names=['out_files', 'splits'],
                                   function=merge_files),
                      name='merge_files')
    wf.connect([(fixed_fx.get_node('outputspec'), mergefunc,
                                 [('copes', 'copes'),
                                  ('varcopes', 'varcopes'),
                                  ])])
    wf.connect(mergefunc, 'out_files', registration, 'inputspec.source_files')

    def split_files(in_files, splits):
        copes = in_files[:splits[1]]
        varcopes = in_files[splits[1]:]
        return copes, varcopes

    splitfunc = pe.Node(niu.Function(input_names=['in_files', 'splits'],
                                     output_names=['copes', 'varcopes'],
                                     function=split_files),
                      name='split_files')
    wf.connect(mergefunc, 'splits', splitfunc, 'splits')
    wf.connect(registration, 'outputspec.transformed_files',
               splitfunc, 'in_files')


    """
    Connect to a datasink
    """

    def get_subs(subject_id, conds, model_id, task_id):
        subs = [('_subject_id_%s_' % subject_id, '')]
        subs.append(('_model_id_%d' % model_id, 'model%03d' %model_id))
        subs.append(('task_id_%d/' % task_id, '/task%03d_' % task_id))
        subs.append(('bold_dtype_mcf_mask_smooth_mask_gms_tempfilt_mean_warp_warp',
        'mean'))
        for i in range(len(conds)):
            subs.append(('_flameo%d/cope1.' % i, 'cope%02d.' % (i + 1)))
            subs.append(('_flameo%d/varcope1.' % i, 'varcope%02d.' % (i + 1)))
            subs.append(('_flameo%d/zstat1.' % i, 'zstat%02d.' % (i + 1)))
            subs.append(('_flameo%d/tstat1.' % i, 'tstat%02d.' % (i + 1)))
            subs.append(('_flameo%d/res4d.' % i, 'res4d%02d.' % (i + 1)))
            subs.append(('_warpall%d/cope1_warp_warp.' % i,
                         'cope%02d.' % (i + 1)))
            subs.append(('_warpall%d/varcope1_warp_warp.' % (len(conds) + i),
                         'varcope%02d.' % (i + 1)))
        return subs

    subsgen = pe.Node(niu.Function(input_names=['subject_id', 'conds',
                                                'model_id', 'task_id'],
                                   output_names=['substitutions'],
                                   function=get_subs),
                      name='subsgen')

    datasink = pe.Node(interface=nio.DataSink(),
                       name="datasink")
    wf.connect(infosource, 'subject_id', datasink, 'container')
    wf.connect(infosource, 'subject_id', subsgen, 'subject_id')
    wf.connect(infosource, 'model_id', subsgen, 'model_id')
    wf.connect(infosource, 'task_id', subsgen, 'task_id')
    wf.connect(contrastgen, 'contrasts', subsgen, 'conds')
    wf.connect(subsgen, 'substitutions', datasink, 'substitutions')
    wf.connect([(fixed_fx.get_node('outputspec'), datasink,
                                 [('res4d', 'res4d'),
                                  ('copes', 'copes'),
                                  ('varcopes', 'varcopes'),
                                  ('zstats', 'zstats'),
                                  ('tstats', 'tstats')])
                                 ])
    wf.connect([(splitfunc, datasink,
                 [('copes', 'copes.mni'),
                  ('varcopes', 'varcopes.mni'),
                  ])])
    wf.connect(registration, 'outputspec.transformed_mean', datasink, 'mean.mni')

    """
    Set processing parameters
    """

    hpcutoff = 120.
    preproc.inputs.inputspec.fwhm = 6.0
    gethighpass.inputs.hpcutoff = hpcutoff
    modelspec.inputs.high_pass_filter_cutoff = hpcutoff
    modelfit.inputs.inputspec.bases = {'dgamma': {'derivs': True}}
    modelfit.inputs.inputspec.model_serial_correlations = True
    modelfit.inputs.inputspec.film_threshold = 1000

    datasink.inputs.base_directory = output_dir
    return wf