Example #1
0
def cbf_outlier_detection_initialize():
    od_preproc = pe.Workflow(name='od_preproc')
    od_preproc.base_dir = (os.getcwd())

    od_inputnode = pe.Node(interface=util.IdentityInterface(
        fields=['cl_mcf', 'cl_mcf_par', 'm0_mask']),
                           name='od_inputnode')

    # Artifact Detection with
    od_cl_art = pe.Node(interface=ra.ArtifactDetect(
        use_differences=[True, False],
        use_norm=True,
        norm_threshold=1,
        zintensity_threshold=3,
        parameter_source='FSL',
        mask_type='file'),
                        name="od_cl_art")

    od_outputnode = pe.Node(interface=util.IdentityInterface(
        fields=['od_plot', 'od_outliers', 'od_intensity', 'od_statistic']),
                            name='od_outputnode')

    od_preproc.connect([
        (od_inputnode, od_cl_art, [('cl_mcf', 'realigned_files')]),
        (od_inputnode, od_cl_art, [('cl_mcf_par', 'realignment_parameters')]),
        (od_inputnode, od_cl_art, [('m0_mask', 'mask_file')]),
        (od_cl_art, od_outputnode, [['outlier_files', 'od_outliers']]),
        (od_cl_art, od_outputnode, [['intensity_files', 'od_intensity']]),
        (od_cl_art, od_outputnode, [['plot_files', 'od_plot']]),
        (od_cl_art, od_outputnode, [['statistic_files', 'od_statistic']])
    ])

    return od_preproc
Example #2
0
def test_ad_get_affine_matrix():
    ad = ra.ArtifactDetect()
    matrix = ad._get_affine_matrix(np.array([0]))
    yield assert_equal, matrix, np.eye(4)
    # test translation
    params = [1, 2, 3]
    matrix = ad._get_affine_matrix(params)
    out = np.eye(4)
    out[0:3, 3] = params
    yield assert_equal, matrix, out
    # test rotation
    params = np.array([0, 0, 0, np.pi / 2, np.pi / 2, np.pi / 2])
    matrix = ad._get_affine_matrix(params)
    out = np.array([0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1]).reshape(
        (4, 4))
    yield assert_almost_equal, matrix, out
    # test scaling
    params = np.array([0, 0, 0, 0, 0, 0, 1, 2, 3])
    matrix = ad._get_affine_matrix(params)
    out = np.array([1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1]).reshape(
        (4, 4))
    yield assert_equal, matrix, out
    # test shear
    params = np.array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3])
    matrix = ad._get_affine_matrix(params)
    out = np.array([1, 1, 2, 0, 0, 1, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1]).reshape(
        (4, 4))
    yield assert_equal, matrix, out
Example #3
0
def art_mean_workflow(name="take_mean_art"):
    """Calculates mean image after running art w/ norm = 0.5, z=2
    
    Parameters
    ----------
    name : name of workflow. Default = 'take_mean_art'
    
    Inputs
    ------
    inputspec.realigned_files :
    inputspec.parameter_source :
    inputspec.realignment_parameters :
    
    Outputs
    -------
    outputspec.mean_image :
    
    Returns
    -------
    workflow : mean image workflow
    """
    # define workflow
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as util
    import nipype.algorithms.rapidart as ra  # rapid artifact detection
    wkflw = pe.Workflow(name=name)

    # define nodes
    inputspec = pe.Node(util.IdentityInterface(fields=[
        'realigned_files', 'parameter_source', 'realignment_parameters'
    ]),
                        name='inputspec')

    meanimg = pe.Node(util.Function(input_names=['image', 'art_file'],
                                    output_names=['mean_image'],
                                    function=weight_mean),
                      name='weighted_mean')

    ad = pe.Node(ra.ArtifactDetect(), name='strict_artifact_detect')

    outputspec = pe.Node(util.IdentityInterface(fields=['mean_image']),
                         name='outputspec')

    # inputs
    ad.inputs.zintensity_threshold = 2
    ad.inputs.norm_threshold = 0.5
    ad.inputs.use_differences = [True, False]
    ad.inputs.mask_type = 'spm_global'

    # connections
    wkflw.connect(inputspec, 'parameter_source', ad, 'parameter_source')
    wkflw.connect(inputspec, 'realigned_files', ad, 'realigned_files')
    wkflw.connect(inputspec, 'realignment_parameters', ad,
                  'realignment_parameters')
    wkflw.connect(ad, 'outlier_files', meanimg, 'art_file')
    wkflw.connect(inputspec, 'realigned_files', meanimg, 'image')
    wkflw.connect(meanimg, 'mean_image', outputspec, 'mean_image')
    return wkflw
Example #4
0
def test_ad_get_norm():
    ad = ra.ArtifactDetect()
    params = np.array([
        0, 0, 0, 0, 0, 0, 0, 0, 0, np.pi / 4, np.pi / 4, np.pi / 4, 0, 0, 0,
        -np.pi / 4, -np.pi / 4, -np.pi / 4
    ]).reshape((3, 6))
    norm = ad._calc_norm(params, False)
    yield assert_almost_equal, norm, np.array(
        [18.86436316, 37.74610158, 31.29780829])
    norm = ad._calc_norm(params, True)
    yield assert_almost_equal, norm, np.array([0., 143.72192614, 173.92527131])
Example #5
0
def test_ad_output_filenames():
    ad = ra.ArtifactDetect()
    outputdir = '/tmp'
    f = 'motion.nii'
    outlierfile, intensityfile, statsfile, normfile, plotfile = ad._get_output_filenames(
        f, outputdir)
    yield assert_equal, outlierfile, '/tmp/art.motion_outliers.txt'
    yield assert_equal, intensityfile, '/tmp/global_intensity.motion.txt'
    yield assert_equal, statsfile, '/tmp/stats.motion.txt'
    yield assert_equal, normfile, '/tmp/norm.motion.txt'
    yield assert_equal, plotfile, '/tmp/plot.motion.png'
Example #6
0
def run_artdetect(file4d, param_file, thresh=4, param_source='SPM'):
    startdir = os.getcwd()
    pth, _ = os.path.split(param_file)
    os.chdir(pth)
    ad = rapidart.ArtifactDetect()
    ad.inputs.realigned_files = file4d
    ad.inputs.realignment_parameters = param_file
    ad.inputs.parameter_source = param_source
    ad.inputs.norm_threshold = 1
    ad.inputs.mask_type = 'spm_global'
    ad.inputs.use_differences = [True, False]
    ad.inputs.zintensity_threshold = thresh
    adout = ad.run()
    os.chdir(startdir)
    return adout
Example #7
0
def run_artdetect(file4d, param_file):
    startdir = os.getcwd()
    pth, _ = os.path.split(file4d)
    os.chdir(pth)
    ad = rapidart.ArtifactDetect()
    ad.inputs.realigned_files = file4d
    ad.inputs.realignment_parameters = param_file
    ad.inputs.parameter_source = 'SPM'
    ad.inputs.norm_threshold = 3
    ad.inputs.use_differences = [True, False]
    ad.inputs.zintensity_threshold = 5
    ad.inputs.mask_type = 'thresh'
    ad.inputs.mask_threshold = -100 
    ad.inputs.save_plot = False
    adout = ad.run()
    os.chdir(startdir)
    return adout
Example #8
0
def test_artifactdetect():
    input_map = dict(
        intersect_mask=dict(),
        mask_file=dict(),
        mask_threshold=dict(),
        mask_type=dict(),
        norm_threshold=dict(),
        parameter_source=dict(mandatory=True, ),
        realigned_files=dict(mandatory=True, ),
        realignment_parameters=dict(),
        rotation_threshold=dict(),
        translation_threshold=dict(),
        use_differences=dict(usedefault=True, ),
        use_norm=dict(usedefault=True, ),
        zintensity_threshold=dict(),
    )
    instance = ra.ArtifactDetect()
    for key, metadata in input_map.items():
        for metakey, value in metadata.items():
            yield assert_equal, getattr(instance.inputs.traits()[key],
                                        metakey), value
Example #9
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
Example #10
0
def fsl_run_level_wf(
    model,
    step,
    bids_dir,
    output_dir,
    work_dir,
    subject_id,
    database_path,
    smoothing_fwhm=None,
    smoothing_level=None,
    smoothing_type=None,
    use_rapidart=False,
    detrend_poly=None,
    align_volumes=None,
    smooth_autocorrelations=False,
    despike=False,
    name="fsl_run_level_wf",
):
    """Generate run level workflow for a given model."""
    bids_dir = Path(bids_dir)
    work_dir = Path(work_dir)
    workflow = pe.Workflow(name=name)

    level = step["Level"]

    dimensionality = 3  # Nipype FSL.SUSAN Default
    if smoothing_type == "inp":
        dimensionality = 2

    workflow.__desc__ = ""
    (work_dir / model["Name"]).mkdir(exist_ok=True)

    include_entities = {}
    if "Input" in model:
        if "Include" in model["Input"]:
            include_entities = model["Input"]["Include"]
    include_entities.update({"subject": subject_id})

    getter = pe.Node(
        BIDSGet(
            database_path=database_path,
            fixed_entities=include_entities,
            align_volumes=align_volumes,
        ),
        name="func_select",
    )

    get_info = pe.MapNode(
        GetRunModelInfo(model=step, detrend_poly=detrend_poly),
        iterfield=[
            "metadata_file", "regressor_file", "events_file", "entities"
        ],
        name=f"get_{level}_info",
    )

    despiker = pe.MapNode(
        afni.Despike(outputtype="NIFTI_GZ"),
        iterfield=["in_file"],
        name="despiker",
    )

    realign_runs = pe.MapNode(
        fsl.MCFLIRT(output_type="NIFTI_GZ", interpolation="sinc"),
        iterfield=["in_file", "ref_file"],
        name="func_realign",
    )

    wrangle_volumes = pe.MapNode(
        IdentityInterface(fields=["functional_file"]),
        iterfield=["functional_file"],
        name="wrangle_volumes",
    )

    specify_model = pe.MapNode(
        modelgen.SpecifyModel(high_pass_filter_cutoff=-1.0,
                              input_units="secs"),
        iterfield=["functional_runs", "subject_info", "time_repetition"],
        name=f"model_{level}_specify",
    )

    fit_model = pe.MapNode(
        IdentityInterface(
            fields=[
                "session_info", "interscan_interval", "contrasts",
                "functional_data"
            ],
            mandatory_inputs=True,
        ),
        iterfield=[
            "functional_data", "session_info", "interscan_interval",
            "contrasts"
        ],
        name=f"model_{level}_fit",
    )

    first_level_design = pe.MapNode(
        fsl.Level1Design(
            bases={"dgamma": {
                "derivs": False
            }},
            model_serial_correlations=False,
        ),
        iterfield=["session_info", "interscan_interval", "contrasts"],
        name=f"model_{level}_design",
    )

    generate_model = pe.MapNode(
        fsl.FEATModel(output_type="NIFTI_GZ"),
        iterfield=["fsf_file", "ev_files"],
        name=f"model_{level}_generate",
    )

    estimate_model = pe.MapNode(
        fsl.FILMGLS(
            threshold=0.0,  # smooth_autocorr=True
            output_type="NIFTI_GZ",
            results_dir="results",
            smooth_autocorr=False,
            autocorr_noestimate=True,
        ),
        iterfield=["design_file", "in_file", "tcon_file"],
        name=f"model_{level}_estimate",
    )

    if smooth_autocorrelations:
        first_level_design.inputs.model_serial_correlations = True
        estimate_model.inputs.smooth_autocorr = True
        estimate_model.inputs.autocorr_noestimate = False

    calculate_p = pe.MapNode(
        fsl.ImageMaths(output_type="NIFTI_GZ",
                       op_string="-ztop",
                       suffix="_pval"),
        iterfield=["in_file"],
        name=f"model_{level}_caculate_p",
    )

    image_pattern = ("[sub-{subject}/][ses-{session}/]"
                     "[sub-{subject}_][ses-{session}_]"
                     "task-{task}_[acq-{acquisition}_]"
                     "[rec-{reconstruction}_][run-{run}_]"
                     "[echo-{echo}_][space-{space}_]contrast-{contrast}_"
                     "stat-{stat<effect|variance|z|p|t|F>}_statmap.nii.gz")

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

    reshape_rapidart = pe.MapNode(
        Function(
            input_names=[
                "run_info", "functional_file", "outlier_file",
                "contrast_entities"
            ],
            output_names=["run_info", "contrast_entities"],
            function=utils.reshape_ra,
        ),
        iterfield=[
            "run_info", "functional_file", "outlier_file", "contrast_entities"
        ],
        name="reshape_rapidart",
    )

    mean_img = pe.MapNode(
        fsl.ImageMaths(output_type="NIFTI_GZ",
                       op_string="-Tmean",
                       suffix="_mean"),
        iterfield=["in_file", "mask_file"],
        name="smooth_susan_avgimg",
    )

    median_img = pe.MapNode(
        fsl.ImageStats(output_type="NIFTI_GZ", op_string="-k %s -p 50"),
        iterfield=["in_file", "mask_file"],
        name="smooth_susan_medimg",
    )

    merge = pe.Node(Merge(2, axis="hstack"), name="smooth_merge")

    run_susan = pe.MapNode(
        fsl.SUSAN(output_type="NIFTI_GZ"),
        iterfield=["in_file", "brightness_threshold", "usans"],
        name="smooth_susan",
    )

    mask_functional = pe.MapNode(ApplyMask(),
                                 iterfield=["in_file", "mask_file"],
                                 name="mask_functional")

    # Exists solely to correct undesirable behavior of FSL
    # that results in loss of constant columns
    correct_matrices = pe.MapNode(
        Function(
            input_names=["design_matrix"],
            output_names=["design_matrix"],
            function=utils.correct_matrix,
        ),
        iterfield=["design_matrix"],
        run_without_submitting=True,
        name=f"correct_{level}_matrices",
    )

    collate = pe.Node(
        MergeAll(
            fields=[
                "effect_maps",
                "variance_maps",
                "zscore_maps",
                "pvalue_maps",
                "tstat_maps",
                "contrast_metadata",
            ],
            check_lengths=True,
        ),
        name=f"collate_{level}",
    )

    collate_outputs = pe.Node(
        CollateWithMetadata(
            fields=[
                "effect_maps", "variance_maps", "zscore_maps", "pvalue_maps",
                "tstat_maps"
            ],
            field_to_metadata_map={
                "effect_maps": {
                    "stat": "effect"
                },
                "variance_maps": {
                    "stat": "variance"
                },
                "zscore_maps": {
                    "stat": "z"
                },
                "pvalue_maps": {
                    "stat": "p"
                },
                "tstat_maps": {
                    "stat": "t"
                },
            },
        ),
        name=f"collate_{level}_outputs",
    )

    plot_matrices = pe.MapNode(
        PlotMatrices(output_dir=output_dir, database_path=database_path),
        iterfield=["mat_file", "con_file", "entities", "run_info"],
        run_without_submitting=True,
        name=f"plot_{level}_matrices",
    )

    ds_contrast_maps = pe.MapNode(
        BIDSDataSink(base_directory=output_dir, path_patterns=image_pattern),
        iterfield=["entities", "in_file"],
        run_without_submitting=True,
        name=f"ds_{level}_contrast_maps",
    )

    wrangle_outputs = pe.Node(
        IdentityInterface(fields=["contrast_metadata", "contrast_maps"]),
        name=f"wrangle_{level}_outputs",
    )

    # Setup connections among nodes
    workflow.connect([(
        getter,
        get_info,
        [
            ("metadata_files", "metadata_file"),
            ("events_files", "events_file"),
            ("regressor_files", "regressor_file"),
            ("entities", "entities"),
        ],
    )])

    if align_volumes and despike:
        workflow.connect([
            (getter, despiker, [("functional_files", "in_file")]),
            (despiker, realign_runs, [("out_file", "in_file")]),
            (getter, realign_runs, [("reference_files", "ref_file")]),
            (
                realign_runs,
                wrangle_volumes,
                [("out_file", "functional_file")],
            ),
        ])
    elif align_volumes and not despike:
        workflow.connect([
            (
                getter,
                realign_runs,
                [("functional_files", "in_file"),
                 ("reference_files", "ref_file")],
            ),
            (
                realign_runs,
                wrangle_volumes,
                [("out_file", "functional_file")],
            ),
        ])
    elif despike:
        workflow.connect([
            (getter, despiker, [("functional_files", "in_file")]),
            (despiker, wrangle_volumes, [("out_file", "functional_file")]),
        ])
    else:
        workflow.connect([(getter, wrangle_volumes, [("functional_files",
                                                      "functional_file")])])

    if use_rapidart:
        workflow.connect([
            (get_info, run_rapidart, [("motion_parameters",
                                       "realignment_parameters")]),
            (getter, run_rapidart, [("mask_files", "mask_file")]),
            (
                wrangle_volumes,
                run_rapidart,
                [("functional_file", "realigned_files")],
            ),
            (
                run_rapidart,
                reshape_rapidart,
                [("outlier_files", "outlier_file")],
            ),
            (
                get_info,
                reshape_rapidart,
                [("run_info", "run_info"),
                 ("contrast_entities", "contrast_entities")],
            ),
            (wrangle_volumes, reshape_rapidart, [("functional_file",
                                                  "functional_file")]),
            (
                reshape_rapidart,
                specify_model,
                [("run_info", "subject_info")],
            ),
            (reshape_rapidart, plot_matrices, [("run_info", "run_info")]),
            (reshape_rapidart, collate, [("contrast_entities",
                                          "contrast_metadata")]),
        ])
    else:
        workflow.connect([
            (get_info, specify_model, [("run_info", "subject_info")]),
            (get_info, plot_matrices, [("run_info", "run_info")]),
            (
                get_info,
                collate,
                [("contrast_entities", "contrast_metadata")],
            ),
        ])

    if smoothing_level == "l1" or smoothing_level == "run":
        run_susan.inputs.fwhm = smoothing_fwhm
        run_susan.inputs.dimension = dimensionality
        estimate_model.inputs.mask_size = smoothing_fwhm
        workflow.connect([
            (wrangle_volumes, mean_img, [("functional_file", "in_file")]),
            (
                wrangle_volumes,
                median_img,
                [("functional_file", "in_file")],
            ),
            (getter, mean_img, [("mask_files", "mask_file")]),
            (getter, median_img, [("mask_files", "mask_file")]),
            (mean_img, merge, [("out_file", "in1")]),
            (median_img, merge, [("out_stat", "in2")]),
            (wrangle_volumes, run_susan, [("functional_file", "in_file")]),
            (
                median_img,
                run_susan,
                [(
                    ("out_stat", utils.get_btthresh),
                    "brightness_threshold",
                )],
            ),
            (merge, run_susan, [(("out", utils.get_usans), "usans")]),
            (getter, mask_functional, [("mask_files", "mask_file")]),
            (run_susan, mask_functional, [("smoothed_file", "in_file")]),
            (
                mask_functional,
                specify_model,
                [("out_file", "functional_runs")],
            ),
            (
                mask_functional,
                fit_model,
                [("out_file", "functional_data")],
            ),
        ])

    else:
        workflow.connect([
            (getter, mask_functional, [("mask_files", "mask_file")]),
            (
                wrangle_volumes,
                mask_functional,
                [("functional_file", "in_file")],
            ),
            (
                mask_functional,
                specify_model,
                [("out_file", "functional_runs")],
            ),
            (
                mask_functional,
                fit_model,
                [("out_file", "functional_data")],
            ),
        ])

    workflow.connect([
        (
            get_info,
            specify_model,
            [("repetition_time", "time_repetition")],
        ),
        (specify_model, fit_model, [("session_info", "session_info")]),
        (
            get_info,
            fit_model,
            [("repetition_time", "interscan_interval"),
             ("run_contrasts", "contrasts")],
        ),
        (
            fit_model,
            first_level_design,
            [
                ("interscan_interval", "interscan_interval"),
                ("session_info", "session_info"),
                ("contrasts", "contrasts"),
            ],
        ),
        (first_level_design, generate_model, [("fsf_files", "fsf_file")]),
        (first_level_design, generate_model, [("ev_files", "ev_files")]),
    ])

    if detrend_poly:
        workflow.connect([
            (
                generate_model,
                correct_matrices,
                [("design_file", "design_matrix")],
            ),
            (
                correct_matrices,
                plot_matrices,
                [("design_matrix", "mat_file")],
            ),
            (
                correct_matrices,
                estimate_model,
                [("design_matrix", "design_file")],
            ),
        ])

    else:
        workflow.connect([
            (generate_model, plot_matrices, [("design_file", "mat_file")]),
            (
                generate_model,
                estimate_model,
                [("design_file", "design_file")],
            ),
        ])

    workflow.connect([
        (getter, plot_matrices, [("entities", "entities")]),
        (generate_model, plot_matrices, [("con_file", "con_file")]),
        (fit_model, estimate_model, [("functional_data", "in_file")]),
        (generate_model, estimate_model, [("con_file", "tcon_file")]),
        (
            estimate_model,
            calculate_p,
            [(("zstats", utils.flatten), "in_file")],
        ),
        (
            estimate_model,
            collate,
            [
                ("copes", "effect_maps"),
                ("varcopes", "variance_maps"),
                ("zstats", "zscore_maps"),
                ("tstats", "tstat_maps"),
            ],
        ),
        (calculate_p, collate, [("out_file", "pvalue_maps")]),
        (
            collate,
            collate_outputs,
            [
                ("effect_maps", "effect_maps"),
                ("variance_maps", "variance_maps"),
                ("zscore_maps", "zscore_maps"),
                ("pvalue_maps", "pvalue_maps"),
                ("tstat_maps", "tstat_maps"),
                ("contrast_metadata", "metadata"),
            ],
        ),
        (
            collate_outputs,
            ds_contrast_maps,
            [("out", "in_file"), ("metadata", "entities")],
        ),
        (
            collate_outputs,
            wrangle_outputs,
            [("metadata", "contrast_metadata"), ("out", "contrast_maps")],
        ),
    ])

    return workflow
Example #11
0
def create_spm_preproc_func_pipeline(data_dir=None,
                                     subject_id=None,
                                     task_list=None):

    ###############################
    ## Set up Nodes
    ###############################

    ds = Node(nio.DataGrabber(infields=['subject_id', 'task_id'],
                              outfields=['func', 'struc']),
              name='datasource')
    ds.inputs.base_directory = os.path.abspath(data_dir + '/' + subject_id)
    ds.inputs.template = '*'
    ds.inputs.sort_filelist = True
    ds.inputs.template_args = {'func': [['task_id']], 'struc': []}
    ds.inputs.field_template = {
        'func': 'Functional/Raw/%s/func.nii',
        'struc': 'Structural/SPGR/spgr.nii'
    }
    ds.inputs.subject_id = subject_id
    ds.inputs.task_id = task_list
    ds.iterables = ('task_id', task_list)
    # ds.run().outputs #show datafiles

    # #Setup Data Sinker for writing output files
    # datasink = Node(nio.DataSink(), name='sinker')
    # datasink.inputs.base_directory = '/path/to/output'
    # workflow.connect(realigner, 'realignment_parameters', datasink, 'motion.@par')
    # datasink.inputs.substitutions = [('_variable', 'variable'),('file_subject_', '')]

    #Get Timing Acquisition for slice timing
    tr = 2
    ta = Node(interface=util.Function(input_names=['tr', 'n_slices'],
                                      output_names=['ta'],
                                      function=get_ta),
              name="ta")
    ta.inputs.tr = tr

    #Slice Timing: sequential ascending
    slice_timing = Node(interface=spm.SliceTiming(), name="slice_timing")
    slice_timing.inputs.time_repetition = tr
    slice_timing.inputs.ref_slice = 1

    #Realignment - 6 parameters - realign to first image of very first series.
    realign = Node(interface=spm.Realign(), name="realign")
    realign.inputs.register_to_mean = True

    #Plot Realignment
    plot_realign = Node(interface=PlotRealignmentParameters(),
                        name="plot_realign")

    #Artifact Detection
    art = Node(interface=ra.ArtifactDetect(), name="art")
    art.inputs.use_differences = [True, False]
    art.inputs.use_norm = True
    art.inputs.norm_threshold = 1
    art.inputs.zintensity_threshold = 3
    art.inputs.mask_type = 'file'
    art.inputs.parameter_source = 'SPM'

    #Coregister - 12 parameters, cost function = 'nmi', fwhm 7, interpolate, don't mask
    #anatomical to functional mean across all available data.
    coregister = Node(interface=spm.Coregister(), name="coregister")
    coregister.inputs.jobtype = 'estimate'

    # Segment structural, gray/white/csf,mni,
    segment = Node(interface=spm.Segment(), name="segment")
    segment.inputs.save_bias_corrected = True

    #Normalize - structural to MNI - then apply this to the coregistered functionals
    normalize = Node(interface=spm.Normalize(), name="normalize")
    normalize.inputs.template = os.path.abspath(t1_template_file)

    #Plot normalization Check
    plot_normalization_check = Node(interface=Plot_Coregistration_Montage(),
                                    name="plot_normalization_check")
    plot_normalization_check.inputs.canonical_img = canonical_file

    #Create Mask
    compute_mask = Node(interface=ComputeMask(), name="compute_mask")
    #remove lower 5% of histogram of mean image
    compute_mask.inputs.m = .05

    #Smooth
    #implicit masking (.im) = 0, dtype = 0
    smooth = Node(interface=spm.Smooth(), name="smooth")
    fwhmlist = [0, 5, 8]
    smooth.iterables = ('fwhm', fwhmlist)

    #Create Covariate matrix
    make_covariates = Node(interface=Create_Covariates(),
                           name="make_covariates")

    ###############################
    ## Create Pipeline
    ###############################

    Preprocessed = Workflow(name="Preprocessed")
    Preprocessed.base_dir = os.path.abspath(data_dir + '/' + subject_id +
                                            '/Functional')

    Preprocessed.connect([
        (ds, ta, [(('func', get_n_slices), "n_slices")]),
        (ta, slice_timing, [("ta", "time_acquisition")]),
        (ds, slice_timing, [
            ('func', 'in_files'),
            (('func', get_n_slices), "num_slices"),
            (('func', get_slice_order), "slice_order"),
        ]),
        (slice_timing, realign, [('timecorrected_files', 'in_files')]),
        (realign, compute_mask, [('mean_image', 'mean_volume')]),
        (realign, coregister, [('mean_image', 'target')]),
        (ds, coregister, [('struc', 'source')]),
        (coregister, segment, [('coregistered_source', 'data')]),
        (segment, normalize, [
            ('transformation_mat', 'parameter_file'),
            ('bias_corrected_image', 'source'),
        ]),
        (realign, normalize, [('realigned_files', 'apply_to_files'),
                              (('realigned_files', get_vox_dims),
                               'write_voxel_sizes')]),
        (normalize, smooth, [('normalized_files', 'in_files')]),
        (compute_mask, art, [('brain_mask', 'mask_file')]),
        (realign, art, [('realignment_parameters', 'realignment_parameters')]),
        (realign, art, [('realigned_files', 'realigned_files')]),
        (realign, plot_realign, [('realignment_parameters',
                                  'realignment_parameters')]),
        (normalize, plot_normalization_check, [('normalized_files', 'wra_img')
                                               ]),
        (realign, make_covariates, [('realignment_parameters',
                                     'realignment_parameters')]),
        (art, make_covariates, [('outlier_files', 'spike_id')]),
    ])
    return Preprocessed
Example #12
0
level1_workflow = pe.Workflow(name='level1flow')

preproc = create_featreg_preproc(whichvol='first')

modelfit = create_modelfit_workflow()

fixed_fx = create_fixed_effects_flow()
"""
Add artifact detection and model specification nodes between the preprocessing
and modelfitting workflows.
"""

art = pe.MapNode(
    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(model.SpecifyModel(), name="modelspec")

level1_workflow.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')]),
Example #13
0
def create_denoise_pipeline(name='denoise'):
    # workflow
    denoise = Workflow(name='denoise')
    # Define nodes
    inputnode = Node(interface=util.IdentityInterface(fields=[
        'anat_brain', 'brain_mask', 'epi2anat_dat', 'unwarped_mean',
        'epi_coreg', 'moco_par', 'highpass_sigma', 'lowpass_sigma', 'tr'
    ]),
                     name='inputnode')
    outputnode = Node(interface=util.IdentityInterface(fields=[
        'wmcsf_mask', 'brain_mask_resamp', 'brain_mask2epi', 'combined_motion',
        'outlier_files', 'intensity_files', 'outlier_stats', 'outlier_plots',
        'mc_regressor', 'mc_F', 'mc_pF', 'comp_regressor', 'comp_F', 'comp_pF',
        'normalized_file'
    ]),
                      name='outputnode')
    # run fast to get tissue probability classes
    fast = Node(fsl.FAST(), name='fast')
    denoise.connect([(inputnode, fast, [('anat_brain', 'in_files')])])

    # functions to select tissue classes
    def selectindex(files, idx):
        import numpy as np
        from nipype.utils.filemanip import filename_to_list, list_to_filename
        return list_to_filename(
            np.array(filename_to_list(files))[idx].tolist())

    def selectsingle(files, idx):
        return files[idx]

    # resample tissue classes
    resample_tissue = MapNode(afni.Resample(resample_mode='NN',
                                            outputtype='NIFTI_GZ'),
                              iterfield=['in_file'],
                              name='resample_tissue')
    denoise.connect([
        (inputnode, resample_tissue, [('epi_coreg', 'master')]),
        (fast, resample_tissue, [(('partial_volume_files', selectindex,
                                   [0, 2]), 'in_file')]),
    ])
    # binarize tissue classes
    binarize_tissue = MapNode(
        fsl.ImageMaths(op_string='-nan -thr 0.99 -ero -bin'),
        iterfield=['in_file'],
        name='binarize_tissue')
    denoise.connect([
        (resample_tissue, binarize_tissue, [('out_file', 'in_file')]),
    ])
    # combine tissue classes to noise mask
    wmcsf_mask = Node(fsl.BinaryMaths(operation='add',
                                      out_file='wmcsf_mask_lowres.nii.gz'),
                      name='wmcsf_mask')
    denoise.connect([(binarize_tissue, wmcsf_mask,
                      [(('out_file', selectsingle, 0), 'in_file'),
                       (('out_file', selectsingle, 1), 'operand_file')]),
                     (wmcsf_mask, outputnode, [('out_file', 'wmcsf_mask')])])
    # resample brain mask
    resample_brain = Node(afni.Resample(
        resample_mode='NN',
        outputtype='NIFTI_GZ',
        out_file='T1_brain_mask_lowres.nii.gz'),
                          name='resample_brain')
    denoise.connect([(inputnode, resample_brain, [('brain_mask', 'in_file'),
                                                  ('epi_coreg', 'master')]),
                     (resample_brain, outputnode, [('out_file',
                                                    'brain_mask_resamp')])])
    # project brain mask into original epi space fpr quality assessment
    brainmask2epi = Node(fs.ApplyVolTransform(
        interp='nearest',
        inverse=True,
        transformed_file='T1_brain_mask2epi.nii.gz',
    ),
                         name='brainmask2epi')
    denoise.connect([
        (inputnode, brainmask2epi, [('brain_mask', 'target_file'),
                                    ('epi2anat_dat', 'reg_file'),
                                    ('unwarped_mean', 'source_file')]),
        (brainmask2epi, outputnode, [('transformed_file', 'brain_mask2epi')])
    ])
    # perform artefact detection
    artefact = Node(ra.ArtifactDetect(save_plot=True,
                                      use_norm=True,
                                      parameter_source='FSL',
                                      mask_type='file',
                                      norm_threshold=1,
                                      zintensity_threshold=3,
                                      use_differences=[True, False]),
                    name='artefact')
    artefact.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (inputnode, artefact, [('epi_coreg', 'realigned_files'),
                               ('moco_par', 'realignment_parameters')]),
        (resample_brain, artefact, [('out_file', 'mask_file')]),
        (artefact, outputnode, [('norm_files', 'combined_motion'),
                                ('outlier_files', 'outlier_files'),
                                ('intensity_files', 'intensity_files'),
                                ('statistic_files', 'outlier_stats'),
                                ('plot_files', 'outlier_plots')])
    ])
    # Compute motion regressors
    motreg = Node(util.Function(
        input_names=['motion_params', 'order', 'derivatives'],
        output_names=['out_files'],
        function=motion_regressors),
                  name='getmotionregress')
    motreg.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, motreg, [('moco_par', 'motion_params')])])
    # Create a filter to remove motion and art confounds
    createfilter1 = Node(util.Function(
        input_names=['motion_params', 'comp_norm', 'outliers', 'detrend_poly'],
        output_names=['out_files'],
        function=build_filter1),
                         name='makemotionbasedfilter')
    createfilter1.inputs.detrend_poly = 2
    createfilter1.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (motreg, createfilter1, [('out_files', 'motion_params')]),
        (
            artefact,
            createfilter1,
            [  #('norm_files', 'comp_norm'),
                ('outlier_files', 'outliers')
            ]),
        (createfilter1, outputnode, [('out_files', 'mc_regressor')])
    ])
    # regress out motion and art confounds
    filter1 = Node(fsl.GLM(out_f_name='F_mcart.nii.gz',
                           out_pf_name='pF_mcart.nii.gz',
                           out_res_name='rest_mc_denoised.nii.gz',
                           demean=True),
                   name='filtermotion')
    filter1.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, filter1, [('epi_coreg', 'in_file')]),
                     (createfilter1, filter1,
                      [(('out_files', list_to_filename), 'design')]),
                     (filter1, outputnode, [('out_f', 'mc_F'),
                                            ('out_pf', 'mc_pF')])])
    # create filter with compcor components
    createfilter2 = Node(util.Function(input_names=[
        'realigned_file', 'mask_file', 'num_components', 'extra_regressors'
    ],
                                       output_names=['out_files'],
                                       function=extract_noise_components),
                         name='makecompcorfilter')
    createfilter2.inputs.num_components = 6
    createfilter2.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (createfilter1, createfilter2, [(('out_files', list_to_filename),
                                         'extra_regressors')]),
        (filter1, createfilter2, [('out_res', 'realigned_file')]),
        (wmcsf_mask, createfilter2, [('out_file', 'mask_file')]),
        (createfilter2, outputnode, [('out_files', 'comp_regressor')]),
    ])
    # regress compcor and other noise components
    filter2 = Node(fsl.GLM(out_f_name='F_noise.nii.gz',
                           out_pf_name='pF_noise.nii.gz',
                           out_res_name='rest2anat_denoised.nii.gz',
                           demean=True),
                   name='filternoise')
    filter2.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(filter1, filter2, [('out_res', 'in_file')]),
                     (createfilter2, filter2, [('out_files', 'design')]),
                     (resample_brain, filter2, [('out_file', 'mask')]),
                     (filter2, outputnode, [('out_f', 'comp_F'),
                                            ('out_pf', 'comp_pF')])])
    # bandpass filter denoised file
    bandpass_filter = Node(
        fsl.TemporalFilter(out_file='rest_denoised_bandpassed.nii.gz'),
        name='bandpass_filter')
    bandpass_filter.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([(inputnode, bandpass_filter,
                      [('highpass_sigma', 'highpass_sigma'),
                       ('lowpass_sigma', 'lowpass_sigma')]),
                     (filter2, bandpass_filter, [('out_res', 'in_file')])])
    # time-normalize scans
    normalize_time = Node(util.Function(input_names=['in_file', 'tr'],
                                        output_names=['out_file'],
                                        function=time_normalizer),
                          name='normalize_time')
    normalize_time.plugin_args = {'submit_specs': 'request_memory = 17000'}
    denoise.connect([
        (inputnode, normalize_time, [('tr', 'tr')]),
        (bandpass_filter, normalize_time, [('out_file', 'in_file')]),
        (normalize_time, outputnode, [('out_file', 'normalized_file')])
    ])
    return denoise
Example #14
0
def create_spm_preproc(name='preproc'):
    """Create an spm preprocessing workflow with freesurfer registration and
    artifact detection.

    The workflow realigns and smooths and registers the functional images with
    the subject's freesurfer space.

    Example
    -------

    >>> preproc = create_spm_preproc()
    >>> preproc.base_dir = '.'
    >>> preproc.inputs.inputspec.fwhm = 6
    >>> preproc.inputs.inputspec.subject_id = 's1'
    >>> preproc.inputs.inputspec.subjects_dir = '.'
    >>> preproc.inputs.inputspec.functionals = ['f3.nii', 'f5.nii']
    >>> preproc.inputs.inputspec.norm_threshold = 1
    >>> preproc.inputs.inputspec.zintensity_threshold = 3

    Inputs::

         inputspec.functionals : functional runs use 4d nifti
         inputspec.subject_id : freesurfer subject id
         inputspec.subjects_dir : freesurfer subjects dir
         inputspec.fwhm : smoothing fwhm
         inputspec.norm_threshold : norm threshold for outliers
         inputspec.zintensity_threshold : intensity threshold in z-score

    Outputs::

         outputspec.realignment_parameters : realignment parameter files
         outputspec.smoothed_files : smoothed functional files
         outputspec.outlier_files : list of outliers
         outputspec.outlier_stats : statistics of outliers
         outputspec.outlier_plots : images of outliers
         outputspec.mask_file : binary mask file in reference image space
         outputspec.reg_file : registration file that maps reference image to
                                 freesurfer space
         outputspec.reg_cost : cost of registration (useful for detecting misalignment)
    """
    """
    Initialize the workflow
    """

    workflow = pe.Workflow(name=name)
    """
    Define the inputs to this workflow
    """

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold',
        'zintensity_threshold'
    ]),
                        name='inputspec')
    """
    Setup the processing nodes and create the mask generation and coregistration
    workflow
    """

    poplist = lambda x: x.pop()
    realign = pe.Node(spm.Realign(), name='realign')
    workflow.connect(inputnode, 'functionals', realign, 'in_files')
    maskflow = create_getmask_flow()
    workflow.connect([(inputnode, maskflow,
                       [('subject_id', 'inputspec.subject_id'),
                        ('subjects_dir', 'inputspec.subjects_dir')])])
    maskflow.inputs.inputspec.contrast_type = 't2'
    workflow.connect(realign, 'mean_image', maskflow, 'inputspec.source_file')
    smooth = pe.Node(spm.Smooth(), name='smooth')
    workflow.connect(inputnode, 'fwhm', smooth, 'fwhm')
    workflow.connect(realign, 'realigned_files', smooth, 'in_files')
    artdetect = pe.Node(ra.ArtifactDetect(mask_type='file',
                                          parameter_source='SPM',
                                          use_differences=[True, False],
                                          use_norm=True,
                                          save_plot=True),
                        name='artdetect')
    workflow.connect([(inputnode, artdetect,
                       [('norm_threshold', 'norm_threshold'),
                        ('zintensity_threshold', 'zintensity_threshold')])])
    workflow.connect([(realign, artdetect, [
        ('realigned_files', 'realigned_files'),
        ('realignment_parameters', 'realignment_parameters')
    ])])
    workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect,
                     'mask_file')
    """
    Define the outputs of the workflow and connect the nodes to the outputnode
    """

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        "realignment_parameters", "smoothed_files", "mask_file", "reg_file",
        "reg_cost", 'outlier_files', 'outlier_stats', 'outlier_plots'
    ]),
                         name="outputspec")
    workflow.connect([
        (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]),
        (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]),
        (maskflow, outputnode, [(("outputspec.mask_file", poplist),
                                 "mask_file")]),
        (realign, outputnode, [('realignment_parameters',
                                'realignment_parameters')]),
        (smooth, outputnode, [('smoothed_files', 'smoothed_files')]),
        (artdetect, outputnode, [('outlier_files', 'outlier_files'),
                                 ('statistic_files', 'outlier_stats'),
                                 ('plot_files', 'outlier_plots')])
    ])
    return workflow
Example #15
0
def create_prep(name='preproc'):
    """ Base preprocessing workflow for task and resting state fMRI
    
    Parameters
    ----------
    name : name of workflow. Default = 'preproc'
    
    Inputs
    ------
    inputspec.fssubject_id : 
    inputspec.fssubject_dir :
    inputspec.func :
    inputspec.highpass :
    inputspec.num_noise_components :
    inputspec.ad_normthresh :
    inputspec.ad_zthresh :
    inputspec.tr :
    inputspec.interleaved :
    inputspec.sliceorder :
    inputspec.compcor_select :
    inputspec.highpass_sigma :
    inputspec.lowpass_sigma :
    inputspec.reg_params :
    inputspec.FM_TEdiff :
    inputspec.FM_Echo_spacing :
    inputspec.FM_sigma :
    
    Outputs
    -------
    outputspec.reference : 
    outputspec.motion_parameters : 
    outputspec.realigned_files :
    outputspec.mask :
    outputspec.smoothed_files :
    outputspec.highpassed_files :
    outputspec.mean :
    outputspec.combined_motion :
    outputspec.outlier_files :
    outputspec.mask :
    outputspec.reg_cost :
    outputspec.reg_file :
    outputspec.noise_components :
    outputspec.tsnr_file :
    outputspec.stddev_file :
    outputspec.filter_file :
    outputspec.scaled_files :
    outputspec.z_img :
    outputspec.motion_plots :
    outputspec.FM_unwarped_mean :
    outputspec.FM_unwarped_epi :
    
    Returns
    -------
    workflow : preprocessing workflow
    """

    import nipype.interfaces.fsl as fsl  # fsl
    import nipype.algorithms.rapidart as ra  # rapid artifact detection
    from nipype.workflows.smri.freesurfer.utils import create_getmask_flow
    from modular_nodes import create_mod_smooth, mod_realign, mod_despike
    import nipype.pipeline.engine as pe
    import nipype.interfaces.utility as util

    preproc = pe.Workflow(name=name)

    # Compcorr node
    compcor = create_compcorr()

    # Input node
    inputnode = pe.Node(util.IdentityInterface(fields=[
        'fssubject_id', 'fssubject_dir', 'func', 'highpass',
        'num_noise_components', 'ad_normthresh', 'ad_zthresh', 'tr',
        'do_slicetime', 'sliceorder', 'compcor_select', 'highpass_freq',
        'lowpass_freq', 'reg_params', 'FM_TEdiff', 'FM_Echo_spacing',
        'FM_sigma', 'motion_correct_node', 'smooth_type', 'surface_fwhm',
        'filter_type', 'timepoints_to_remove', 'do_whitening',
        'regress_before_PCA', 'realign_parameters', 'do_despike', 'anatomical'
    ]),
                        name='inputspec')

    # Separate input node for FWHM
    inputnode_fwhm = pe.Node(util.IdentityInterface(fields=['fwhm']),
                             name='fwhm_input')

    # strip ids
    strip_rois = pe.MapNode(fsl.ExtractROI(),
                            name='extractroi',
                            iterfield='in_file')
    strip_rois.inputs.t_size = -1
    preproc.connect(inputnode, 'timepoints_to_remove', strip_rois, 't_min')

    # convert BOLD images to float
    img2float = pe.MapNode(interface=fsl.ImageMaths(out_data_type='float',
                                                    op_string='',
                                                    suffix='_dtype'),
                           iterfield=['in_file'],
                           name='img2float')

    #afni despike
    despike = pe.MapNode(util.Function(input_names=['in_file', "do_despike"],
                                       output_names=["out_file"],
                                       function=mod_despike),
                         name="despike",
                         iterfield=["in_file"])
    preproc.connect(inputnode, "do_despike", despike, "do_despike")
    # define the motion correction node
    #motion_correct = pe.Node(interface=FmriRealign4d(),
    #                            name='realign')

    motion_correct = pe.Node(util.Function(
        input_names=[
            'node', 'in_file', 'tr', 'do_slicetime', 'sliceorder', "parameters"
        ],
        output_names=['out_file', 'par_file', 'parameter_source'],
        function=mod_realign),
                             name="mod_realign")

    preproc.connect(inputnode, 'motion_correct_node', motion_correct, 'node')

    # construct motion plots
    #plot_motion = pe.MapNode(interface=fsl.PlotMotionParams(in_source='fsl'),
    #                         name='plot_motion',
    #                         iterfield=['in_file'])

    # rapidArt for artifactual timepoint detection
    ad = pe.Node(ra.ArtifactDetect(save_plot=False), name='artifactdetect')

    # extract the mean volume if the first functional run
    meanfunc = art_mean_workflow()

    # generate a freesurfer workflow that will return the mask
    getmask = create_getmask_flow()

    # create a SUSAN smoothing workflow, and smooth each run with
    # 75% of the median value for each run as the brightness
    # threshold.
    smooth = create_mod_smooth(name="modular_smooth", separate_masks=False)
    preproc.connect(inputnode, 'smooth_type', smooth, 'inputnode.smooth_type')
    # choose susan function
    """
    The following node selects smooth or unsmoothed data
    depending on the fwhm. This is because SUSAN defaults
    to smoothing the data with about the voxel size of
    the input data if the fwhm parameter is less than 1/3 of
    the voxel size.
    """
    choosesusan = pe.Node(util.Function(
        input_names=['fwhm', 'motion_files', 'smoothed_files'],
        output_names=['cor_smoothed_files'],
        function=choose_susan),
                          name='select_smooth')

    # scale the median value of each run to 10,000
    meanscale = pe.MapNode(interface=fsl.ImageMaths(suffix='_gms'),
                           iterfield=['in_file', 'op_string'],
                           name='scale_median')

    # determine the median value of the MASKED functional runs
    medianval = pe.MapNode(interface=fsl.ImageStats(op_string='-k %s -p 50'),
                           iterfield=['in_file'],
                           name='compute_median_val')

    # temporal highpass filtering
    highpass = pe.MapNode(interface=fsl.ImageMaths(suffix='_tempfilt'),
                          iterfield=['in_file'],
                          name='highpass')

    # Calculate the z-score of output
    zscore = pe.MapNode(interface=util.Function(
        input_names=['image', 'outliers'],
        output_names=['z_img'],
        function=z_image),
                        name='z_score',
                        iterfield=['image', 'outliers'])

    # declare some node inputs...
    #plot_motion.iterables = ('plot_type', ['rotations', 'translations'])

    #ad.inputs.parameter_source = 'FSL'
    meanfunc.inputs.inputspec.parameter_source = 'FSL'
    ad.inputs.mask_type = 'file'
    ad.inputs.use_differences = [True, False]
    getmask.inputs.inputspec.contrast_type = 't2'
    getmask.inputs.register.out_fsl_file = True
    fssource = getmask.get_node('fssource')

    # make connections...
    preproc.connect(inputnode, 'fssubject_id', getmask, 'inputspec.subject_id')
    preproc.connect(inputnode, 'ad_normthresh', ad, 'norm_threshold')
    preproc.connect(inputnode, 'ad_zthresh', ad, 'zintensity_threshold')
    preproc.connect(inputnode, 'tr', motion_correct, 'tr')
    preproc.connect(inputnode, 'realign_parameters', motion_correct,
                    'parameters')
    preproc.connect(motion_correct, 'parameter_source', ad, 'parameter_source')
    preproc.connect(inputnode, 'do_slicetime', motion_correct, 'do_slicetime')
    preproc.connect(inputnode, 'sliceorder', motion_correct, 'sliceorder')
    preproc.connect(inputnode, 'compcor_select', compcor, 'inputspec.selector')
    preproc.connect(inputnode, 'fssubject_dir', getmask,
                    'inputspec.subjects_dir')

    #preproc.connect(inputnode, 'func',
    #                img2float, 'in_file')
    preproc.connect(inputnode, 'func', strip_rois, 'in_file')
    preproc.connect(strip_rois, 'roi_file', img2float, 'in_file')

    preproc.connect(img2float, 'out_file', despike, "in_file")
    preproc.connect(despike, "out_file", motion_correct, 'in_file')
    #preproc.connect(motion_correct, 'par_file',
    #                plot_motion, 'in_file')
    preproc.connect(motion_correct, 'out_file', meanfunc,
                    'inputspec.realigned_files')
    preproc.connect(motion_correct, 'par_file', meanfunc,
                    'inputspec.realignment_parameters')
    preproc.connect(meanfunc, 'outputspec.mean_image', getmask,
                    'inputspec.source_file')
    preproc.connect(inputnode, 'num_noise_components', compcor,
                    'inputspec.num_components')
    preproc.connect(inputnode, 'regress_before_PCA', compcor,
                    'inputspec.regress_before_PCA')
    preproc.connect(motion_correct, 'out_file', compcor,
                    'inputspec.realigned_file')
    preproc.connect(meanfunc, 'outputspec.mean_image', compcor,
                    'inputspec.mean_file')
    preproc.connect(fssource, 'aseg', compcor, 'inputspec.fsaseg_file')
    preproc.connect(getmask, ('outputspec.reg_file', pickfirst), compcor,
                    'inputspec.reg_file')
    preproc.connect(ad, 'outlier_files', compcor, 'inputspec.outlier_files')
    preproc.connect(motion_correct, 'par_file', compcor,
                    'inputspec.realignment_parameters')
    preproc.connect(motion_correct, 'out_file', ad, 'realigned_files')
    preproc.connect(motion_correct, 'par_file', ad, 'realignment_parameters')
    preproc.connect(getmask, ('outputspec.mask_file', pickfirst), ad,
                    'mask_file')
    preproc.connect(getmask, ('outputspec.mask_file', pickfirst), medianval,
                    'mask_file')
    preproc.connect(inputnode_fwhm, 'fwhm', smooth, 'inputnode.fwhm')
    preproc.connect(motion_correct, 'out_file', smooth, 'inputnode.in_files')
    preproc.connect(getmask, ('outputspec.mask_file', pickfirst), smooth,
                    'inputnode.mask_file')
    preproc.connect(getmask, ('outputspec.reg_file', pickfirst), smooth,
                    'inputnode.reg_file')
    preproc.connect(inputnode, 'surface_fwhm', smooth,
                    'inputnode.surface_fwhm')
    preproc.connect(inputnode, 'fssubject_dir', smooth, 'inputnode.surf_dir')
    preproc.connect(smooth, 'outputnode.smoothed_files', choosesusan,
                    'smoothed_files')
    preproc.connect(motion_correct, 'out_file', choosesusan, 'motion_files')
    preproc.connect(inputnode_fwhm, 'fwhm', choosesusan, 'fwhm')
    preproc.connect(choosesusan, 'cor_smoothed_files', meanscale, 'in_file')
    preproc.connect(choosesusan, 'cor_smoothed_files', medianval, 'in_file')
    preproc.connect(medianval, ('out_stat', getmeanscale), meanscale,
                    'op_string')
    preproc.connect(inputnode, ('highpass', highpass_operand), highpass,
                    'op_string')
    preproc.connect(meanscale, 'out_file', highpass, 'in_file')
    preproc.connect(highpass, 'out_file', zscore, 'image')
    preproc.connect(ad, 'outlier_files', zscore, 'outliers')

    # create output node
    outputnode = pe.Node(interface=util.IdentityInterface(fields=[
        'mean', 'motion_parameters', 'realigned_files', 'smoothed_files',
        'highpassed_files', 'combined_motion', 'outlier_files',
        'outlier_stat_files', 'mask', 'reg_cost', 'reg_file', 'reg_fsl_file',
        'noise_components', 'tsnr_file', 'stddev_file', 'tsnr_detrended',
        'filter_file', 'scaled_files', 'unmasked_fullspectrum', 'z_img',
        'motion_plots', 'FM_unwarped_epi', 'FM_unwarped_mean', 'vsm_file',
        'bandpassed_file', 'intensity_files', 'noise_mask', 'csf_mask'
    ]),
                         name='outputspec')

    # make output connection
    preproc.connect(meanfunc, 'outputspec.mean_image', outputnode, 'mean')
    preproc.connect(motion_correct, 'par_file', outputnode,
                    'motion_parameters')
    preproc.connect(motion_correct, 'out_file', outputnode, 'realigned_files')
    preproc.connect(highpass, 'out_file', outputnode, 'highpassed_files')
    preproc.connect(ad, 'norm_files', outputnode, 'combined_motion')
    preproc.connect(ad, 'outlier_files', outputnode, 'outlier_files')
    preproc.connect(ad, 'intensity_files', outputnode, 'intensity_files')
    preproc.connect(ad, 'statistic_files', outputnode, 'outlier_stat_files')
    preproc.connect(compcor, 'outputspec.noise_components', outputnode,
                    'noise_components')
    preproc.connect(compcor, 'outputspec.noise_mask', outputnode, 'noise_mask')
    preproc.connect(compcor, 'outputspec.csf_mask', outputnode, 'csf_mask')
    preproc.connect(getmask, 'outputspec.mask_file', outputnode, 'mask')
    preproc.connect(getmask, 'register.out_fsl_file', outputnode,
                    'reg_fsl_file')
    preproc.connect(getmask, 'outputspec.reg_file', outputnode, 'reg_file')
    preproc.connect(getmask, 'outputspec.reg_cost', outputnode, 'reg_cost')
    preproc.connect(choosesusan, 'cor_smoothed_files', outputnode,
                    'smoothed_files')
    preproc.connect(compcor, 'outputspec.tsnr_file', outputnode, 'tsnr_file')
    preproc.connect(compcor, 'outputspec.stddev_file', outputnode,
                    'stddev_file')
    preproc.connect(compcor, 'outputspec.tsnr_detrended', outputnode,
                    'tsnr_detrended')
    preproc.connect(zscore, 'z_img', outputnode, 'z_img')
    #preproc.connect(plot_motion,'out_file',
    #                outputnode,'motion_plots')

    return preproc
Example #16
0
def create_spm_preproc(c, name='preproc'):
    """Create an spm preprocessing workflow with freesurfer registration and
artifact detection.

The workflow realigns and smooths and registers the functional images with
the subject's freesurfer space.

Example
-------

>>> preproc = create_spm_preproc()
>>> preproc.base_dir = '.'
>>> preproc.inputs.inputspec.fwhm = 6
>>> preproc.inputs.inputspec.subject_id = 's1'
>>> preproc.inputs.inputspec.subjects_dir = '.'
>>> preproc.inputs.inputspec.functionals = ['f3.nii', 'f5.nii']
>>> preproc.inputs.inputspec.norm_threshold = 1
>>> preproc.inputs.inputspec.zintensity_threshold = 3

Inputs::

inputspec.functionals : functional runs use 4d nifti
inputspec.subject_id : freesurfer subject id
inputspec.subjects_dir : freesurfer subjects dir
inputspec.fwhm : smoothing fwhm
inputspec.norm_threshold : norm threshold for outliers
inputspec.zintensity_threshold : intensity threshold in z-score

Outputs::

outputspec.realignment_parameters : realignment parameter files
outputspec.smoothed_files : smoothed functional files
outputspec.outlier_files : list of outliers
outputspec.outlier_stats : statistics of outliers
outputspec.outlier_plots : images of outliers
outputspec.mask_file : binary mask file in reference image space
outputspec.reg_file : registration file that maps reference image to
freesurfer space
outputspec.reg_cost : cost of registration (useful for detecting misalignment)
"""
    from nipype.workflows.smri.freesurfer.utils import create_getmask_flow
    import nipype.algorithms.rapidart as ra
    import nipype.interfaces.spm as spm
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    import nipype.interfaces.io as nio
    """
Initialize the workflow
"""

    workflow = pe.Workflow(name=name)
    """
Define the inputs to this workflow
"""

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold',
        'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder', 'node',
        'csf_prob', 'wm_prob', 'gm_prob'
    ]),
                        name='inputspec')
    """
Setup the processing nodes and create the mask generation and coregistration
workflow
"""

    poplist = lambda x: x.pop()
    #realign = pe.Node(spm.Realign(), name='realign')

    sym_func = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_link'],
                                    function=do_symlink),
                       name='func_symlink')

    realign = pe.Node(niu.Function(
        input_names=['node', 'in_file', 'tr', 'do_slicetime', 'sliceorder'],
        output_names=['out_file', 'par_file'],
        function=mod_realign),
                      name="mod_realign")

    mean = art_mean_workflow()
    workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files')
    workflow.connect(realign, 'par_file', mean,
                     'inputspec.realignment_parameters')
    mean.inputs.inputspec.parameter_source = 'FSL'  # Modular realign puts it in FSL format for consistency

    #workflow.connect(inputnode, 'functionals', realign, 'in_file')
    workflow.connect(inputnode, 'functionals', sym_func, 'in_file')
    workflow.connect(sym_func, 'out_link', realign, 'in_file')

    workflow.connect(inputnode, 'tr', realign, 'tr')
    workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime')
    workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder')
    workflow.connect(inputnode, 'node', realign, 'node')

    maskflow = create_getmask_flow()
    workflow.connect([(inputnode, maskflow,
                       [('subject_id', 'inputspec.subject_id'),
                        ('subjects_dir', 'inputspec.subjects_dir')])])
    maskflow.inputs.inputspec.contrast_type = 't2'
    workflow.connect(mean, 'outputspec.mean_image', maskflow,
                     'inputspec.source_file')
    smooth = pe.Node(spm.Smooth(), name='smooth')

    normalize = pe.Node(spm.Normalize(jobtype='write'), name='normalize')
    normalize_struct = normalize.clone('normalize_struct')
    segment = pe.Node(spm.Segment(csf_output_type=[True, True, False],
                                  gm_output_type=[True, True, False],
                                  wm_output_type=[True, True, False]),
                      name='segment')

    mergefunc = lambda in1, in2, in3: [in1, in2, in3]

    # merge = pe.Node(niu.Merge(),name='merge')
    merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'],
                                 output_names=['out'],
                                 function=mergefunc),
                    name='merge')
    workflow.connect(inputnode, 'csf_prob', merge, 'in3')
    workflow.connect(inputnode, 'wm_prob', merge, 'in2')
    workflow.connect(inputnode, 'gm_prob', merge, 'in1')

    #workflow.connect(merge,'out', segment,'tissue_prob_maps')

    sym_prob = sym_func.clone('sym_prob')
    workflow.connect(merge, 'out', sym_prob, 'in_file')
    workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps')

    workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), segment,
                     'mask_image')
    workflow.connect(inputnode, 'fwhm', smooth, 'fwhm')

    #sym_brain = sym_func.clone('sym_brain')
    #workflow.connect(realign, 'mean_image', normalize, 'source')
    #workflow.connect(maskflow,'fssource.brain',segment,'data')
    fssource = maskflow.get_node('fssource')
    import nipype.interfaces.freesurfer as fs
    convert_brain = pe.Node(interface=fs.ApplyVolTransform(inverse=True),
                            name='convert')
    workflow.connect(fssource, 'brain', convert_brain, 'target_file')
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst),
                     convert_brain, 'reg_file')
    workflow.connect(mean, 'outputspec.mean_image', convert_brain,
                     'source_file')
    convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'),
                          name='convert2nii')
    workflow.connect(convert_brain, 'transformed_file', convert2nii, 'in_file')
    workflow.connect(convert2nii, 'out_file', segment, 'data')

    workflow.connect(segment, 'transformation_mat', normalize,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_struct,
                     'parameter_file')
    workflow.connect(convert2nii, 'out_file', normalize_struct,
                     'apply_to_files')
    workflow.connect(realign, 'out_file', normalize, 'apply_to_files')
    #normalize.inputs.template='/software/spm8/templates/EPI.nii'
    workflow.connect(normalize, 'normalized_files', smooth, 'in_files')
    #workflow.connect(realign, 'realigned_files', smooth, 'in_files')

    artdetect = pe.Node(ra.ArtifactDetect(mask_type='file',
                                          parameter_source='FSL',
                                          use_differences=[True, False],
                                          use_norm=True,
                                          save_plot=True),
                        name='artdetect')
    workflow.connect([(inputnode, artdetect,
                       [('norm_threshold', 'norm_threshold'),
                        ('zintensity_threshold', 'zintensity_threshold')])])
    workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'),
                                            ('par_file',
                                             'realignment_parameters')])])
    workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect,
                     'mask_file')
    """
Define the outputs of the workflow and connect the nodes to the outputnode
"""

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        "realignment_parameters", "smoothed_files", "mask_file", "mean_image",
        "reg_file", "reg_cost", 'outlier_files', 'outlier_stats',
        'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm',
        'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct',
        'struct_in_functional_space', 'normalization_parameters',
        'reverse_normalize_parameters'
    ]),
                         name="outputspec")
    workflow.connect([
        (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]),
        (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]),
        (maskflow, outputnode, [(("outputspec.mask_file", poplist),
                                 "mask_file")]),
        (realign, outputnode, [('par_file', 'realignment_parameters')]),
        (smooth, outputnode, [('smoothed_files', 'smoothed_files')]),
        (artdetect, outputnode, [('outlier_files', 'outlier_files'),
                                 ('statistic_files', 'outlier_stats'),
                                 ('plot_files', 'outlier_plots'),
                                 ('norm_files', 'norm_components')])
    ])
    workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf')
    workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm')
    workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm')
    workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf')
    workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm')
    workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm')
    workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean')
    workflow.connect(normalize_struct, 'normalized_files', outputnode,
                     'normalized_struct')
    workflow.connect(segment, 'transformation_mat', outputnode,
                     'normalization_parameters')
    workflow.connect(segment, 'inverse_transformation_mat', outputnode,
                     'reverse_normalize_parameters')
    workflow.connect(convert2nii, 'out_file', outputnode,
                     'struct_in_functional_space')

    workflow.inputs.inputspec.fwhm = c.fwhm
    workflow.inputs.inputspec.subjects_dir = c.surf_dir
    workflow.inputs.inputspec.norm_threshold = c.norm_thresh
    workflow.inputs.inputspec.zintensity_threshold = c.z_thresh
    workflow.inputs.inputspec.node = c.motion_correct_node
    workflow.inputs.inputspec.tr = c.TR
    workflow.inputs.inputspec.do_slicetime = c.do_slicetiming
    workflow.inputs.inputspec.sliceorder = c.SliceOrder
    workflow.inputs.inputspec.csf_prob = c.csf_prob
    workflow.inputs.inputspec.gm_prob = c.grey_prob
    workflow.inputs.inputspec.wm_prob = c.white_prob
    workflow.base_dir = c.working_dir
    workflow.config = {'execution': {'crashdump_dir': c.crash_dir}}

    datagrabber = get_dataflow(c)

    workflow.connect(datagrabber, 'func', inputnode, 'functionals')

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']),
                         name='subject_names')
    if not c.test_mode:
        infosource.iterables = ('subject_id', c.subjects)
    else:
        infosource.iterables = ('subject_id', c.subjects[:1])

    workflow.connect(infosource, 'subject_id', inputnode, 'subject_id')
    workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id')
    sub = lambda x: [('_subject_id_%s' % x, '')]

    sinker = pe.Node(nio.DataSink(), name='sinker')
    workflow.connect(infosource, 'subject_id', sinker, 'container')
    workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions')
    sinker.inputs.base_directory = c.sink_dir
    outputspec = workflow.get_node('outputspec')
    workflow.connect(outputspec, 'realignment_parameters', sinker,
                     'spm_preproc.realignment_parameters')
    workflow.connect(outputspec, 'smoothed_files', sinker,
                     'spm_preproc.smoothed_outputs')
    workflow.connect(outputspec, 'outlier_files', sinker,
                     'spm_preproc.art.@outlier_files')
    workflow.connect(outputspec, 'outlier_stats', sinker,
                     'spm_preproc.art.@outlier_stats')
    workflow.connect(outputspec, 'outlier_plots', sinker,
                     'spm_preproc.art.@outlier_plots')
    workflow.connect(outputspec, 'norm_components', sinker,
                     'spm_preproc.art.@norm')
    workflow.connect(outputspec, 'reg_file', sinker,
                     'spm_preproc.bbreg.@reg_file')
    workflow.connect(outputspec, 'reg_cost', sinker,
                     'spm_preproc.bbreg.@reg_cost')
    workflow.connect(outputspec, 'mask_file', sinker,
                     'spm_preproc.mask.@mask_file')
    workflow.connect(outputspec, 'mod_csf', sinker,
                     'spm_preproc.segment.mod.@csf')
    workflow.connect(outputspec, 'mod_wm', sinker,
                     'spm_preproc.segment.mod.@wm')
    workflow.connect(outputspec, 'mod_gm', sinker,
                     'spm_preproc.segment.mod.@gm')
    workflow.connect(outputspec, 'unmod_csf', sinker,
                     'spm_preproc.segment.unmod.@csf')
    workflow.connect(outputspec, 'unmod_wm', sinker,
                     'spm_preproc.segment.unmod.@wm')
    workflow.connect(outputspec, 'unmod_gm', sinker,
                     'spm_preproc.segment.unmod.@gm')
    workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean')
    workflow.connect(outputspec, 'normalized_struct', sinker,
                     'spm_preproc.normalized_struct')
    workflow.connect(outputspec, 'normalization_parameters', sinker,
                     'spm_preproc.normalization_parameters.@forward')
    workflow.connect(outputspec, 'reverse_normalize_parameters', sinker,
                     'spm_preproc.normalization_parameters.@reverse')
    workflow.connect(outputspec, 'struct_in_functional_space', sinker,
                     'spm_preproc.struct_in_func_space')

    return workflow
def analyze_openfmri_dataset(data_dir, subject=None, model_id=None, work_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()

    """
    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 = [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']),
                         name='infosource')
    if subject is None:
        infosource.iterables = [('subject_id', subjects),
            ('model_id', [model_id])]
    else:
        infosource.iterables = [('subject_id',
                                 [subjects[subjects.index(subject)]]),
                                ('model_id', [model_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',
                                                   'model_id'],
                                         outfields=['anat', 'bold', 'behav']),
                         name='datasource')
    datasource.inputs.base_directory = data_dir
    datasource.inputs.template = '*'
    datasource.inputs.field_template = {'anat': '%s/anatomy/highres001.nii.gz',
                                'bold': '%s/BOLD/task001_r*/bold.nii.gz',
                                'behav': ('%s/model/model%03d/onsets/task001_'
                                          'run%03d/cond*.txt')}
    datasource.inputs.template_args = {'anat': [['subject_id']],
                                       'bold': [['subject_id']],
                                       'behav': [['subject_id', 'model_id',
                                                  'run_id']]}
    datasource.inputs.sorted = 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, 'subject_id', datasource, 'subject_id')
    wf.connect(infosource, 'model_id', datasource, 'model_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(base_dir, model_id, conds):
        import numpy as np
        import os
        contrast_file = os.path.join(base_dir, 'models', 'model%03d' % model_id,
                                     'task_contrasts.txt')
        contrast_def = np.genfromtxt(contrast_file, dtype=object)
        contrasts = []
        for row in contrast_def:
            con = [row[0], 'T', ['cond%03d' % i  for i in range(len(conds))],
                   row[1:].astype(float).tolist()]
            contrasts.append(con)
        return contrasts

    contrastgen = pe.Node(niu.Function(input_names=['base_dir', 'model_id',
                                                    'conds'],
                                       output_names=['contrasts'],
                                       function=get_contrasts),
                          name='contrastgen')
    contrastgen.inputs.base_dir = data_dir

    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(infosource, 'model_id', contrastgen, 'model_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'),
                                       ])
                ])

    """
    Connect to a datasink
    """

    def get_subs(subject_id, conds):
        subs = [('_subject_id_%s/' % subject_id, '')]
        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)))
        return subs

    subsgen = pe.Node(niu.Function(input_names=['subject_id', 'conds'],
                                   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(subjinfo, 'conds', 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')])
                                 ])

    """
    Set processing parameters
    """

    hpcutoff = 120.
    subjinfo.inputs.task_id = 1
    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

    if work_dir is None:
        work_dir = os.path.join(os.getcwd(), 'working')
    wf.base_dir = work_dir
    datasink.inputs.base_directory = os.path.join(work_dir, 'output')
    wf.config['execution'] = dict(crashdump_dir=os.path.join(work_dir,
                                                             'crashdumps'),
                                  stop_on_first_crash=True)
    wf.run('MultiProc', plugin_args={'n_procs': 2})
Example #18
0
def create_workflow(func_runs,
                    subject_id,
                    subjects_dir,
                    fwhm,
                    slice_times,
                    highpass_frequency,
                    lowpass_frequency,
                    TR,
                    sink_directory,
                    use_fsl_bp,
                    num_components,
                    whichvol,
                    name='wmaze'):
    
    wf = pe.Workflow(name=name)

    datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run'],
                                         outfields=['func']),
                         name='datasource')
    datasource.inputs.subject_id = subject_id
    datasource.inputs.run = func_runs
    datasource.inputs.template = '/home/data/madlab/data/mri/wmaze/%s/bold/bold_%03d/bold.nii.gz'
    datasource.inputs.sort_filelist = True
    
    # Rename files in case they are named identically
    name_unique = pe.MapNode(util.Rename(format_string='wmaze_%(run)02d'),
                             iterfield = ['in_file', 'run'],
                             name='rename')
    name_unique.inputs.keep_ext = True
    name_unique.inputs.run = func_runs
    wf.connect(datasource, 'func', name_unique, 'in_file')

    # Define the outputs for the preprocessing workflow
    output_fields = ['reference',
                     'motion_parameters',
                     'motion_parameters_plusDerivs',
                     'motionandoutlier_noise_file',
                     'noise_components',
                     'realigned_files',
                     'motion_plots',
                     'mask_file',
                     'smoothed_files',
                     'bandpassed_files',
                     'reg_file',
                     'reg_cost',
                     'reg_fsl_file',
                     'artnorm_files',
                     'artoutlier_files',
                     'artdisplacement_files',
                     'tsnr_file']
        
    outputnode = pe.Node(util.IdentityInterface(fields=output_fields),
                         name='outputspec')

    # Convert functional images to float representation
    img2float = pe.MapNode(fsl.ImageMaths(out_data_type='float',
                                        op_string = '',
                                        suffix='_dtype'),
                           iterfield=['in_file'],
                           name='img2float')
    wf.connect(name_unique, 'out_file', img2float, 'in_file')

    # Run AFNI's despike. This is always run, however, whether this is fed to
    # realign depends on the input configuration
    despiker = pe.MapNode(afni.Despike(outputtype='NIFTI_GZ'),
                          iterfield=['in_file'],
                          name='despike')
    num_threads = 4
    despiker.inputs.environ = {'OMP_NUM_THREADS': '%d' % num_threads}
    despiker.plugin_args = {'bsub_args': '-n %d' % num_threads}
    despiker.plugin_args = {'bsub_args': '-R "span[hosts=1]"'}
    wf.connect(img2float, 'out_file', despiker, 'in_file')

    # Extract the first volume of the first run as the reference 
    extractref = pe.Node(fsl.ExtractROI(t_size=1),
                         iterfield=['in_file'],
                         name = "extractref")
    wf.connect(despiker, ('out_file', pickfirst), extractref, 'in_file')
    wf.connect(despiker, ('out_file', pickvol, 0, whichvol), extractref, 't_min')
    wf.connect(extractref, 'roi_file', outputnode, 'reference')

    if slice_times is not None:
        # Simultaneous motion and slice timing correction with Nipy algorithm
        motion_correct = pe.Node(nipy.SpaceTimeRealigner(), name='motion_correct')
        motion_correct.inputs.tr = TR
        motion_correct.inputs.slice_times = slice_times
        motion_correct.inputs.slice_info = 2
        motion_correct.plugin_args = {'bsub_args': '-n %s' %os.environ['MKL_NUM_THREADS']}
        motion_correct.plugin_args = {'bsub_args': '-R "span[hosts=1]"'}
        wf.connect(despiker, 'out_file', motion_correct, 'in_file')
        wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters')
        wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files')
    else:
        # Motion correct functional runs to the reference (1st volume of 1st run)
        motion_correct =  pe.MapNode(fsl.MCFLIRT(save_mats = True,
                                                 save_plots = True,
                                                 interpolation = 'sinc'),
                                     name = 'motion_correct',
                                     iterfield = ['in_file'])
        wf.connect(despiker, 'out_file', motion_correct, 'in_file')
        wf.connect(extractref, 'roi_file', motion_correct, 'ref_file')
        wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters')
        wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files')

    # Compute TSNR on realigned data regressing polynomials upto order 2
    tsnr = pe.MapNode(TSNR(regress_poly=2), iterfield=['in_file'], name='tsnr')
    wf.connect(motion_correct, 'out_file', tsnr, 'in_file')
    wf.connect(tsnr, 'tsnr_file', outputnode, 'tsnr_file')

    # Plot the estimated motion parameters
    plot_motion = pe.MapNode(fsl.PlotMotionParams(in_source='fsl'),
                             name='plot_motion',
                             iterfield=['in_file'])
    plot_motion.iterables = ('plot_type', ['rotations', 'translations'])
    wf.connect(motion_correct, 'par_file', plot_motion, 'in_file')
    wf.connect(plot_motion, 'out_file', outputnode, 'motion_plots')

    # Register a source file to fs space and create a brain mask in source space
    fssource = pe.Node(nio.FreeSurferSource(),
                       name ='fssource')
    fssource.inputs.subject_id = subject_id
    fssource.inputs.subjects_dir = subjects_dir

    # Extract aparc+aseg brain mask and binarize
    fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'),
                           name ='fs_threshold')
    wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold, 'in_file')

    # Calculate the transformation matrix from EPI space to FreeSurfer space
    # using the BBRegister command
    fs_register = pe.MapNode(fs.BBRegister(init='fsl'),
                             iterfield=['source_file'],
                             name ='fs_register')
    fs_register.inputs.contrast_type = 't2'
    fs_register.inputs.out_fsl_file = True
    fs_register.inputs.subject_id = subject_id
    fs_register.inputs.subjects_dir = subjects_dir
    wf.connect(extractref, 'roi_file', fs_register, 'source_file')
    wf.connect(fs_register, 'out_reg_file', outputnode, 'reg_file')
    wf.connect(fs_register, 'min_cost_file', outputnode, 'reg_cost')
    wf.connect(fs_register, 'out_fsl_file', outputnode, 'reg_fsl_file')

    # Extract wm+csf, brain masks by eroding freesurfer lables
    wmcsf = pe.MapNode(fs.Binarize(), 
                       iterfield=['match', 'binary_file', 'erode'], name='wmcsfmask')
    #wmcsf.inputs.wm_ven_csf = True
    wmcsf.inputs.match = [[2, 41], [4, 5, 14, 15, 24, 31, 43, 44, 63]]
    wmcsf.inputs.binary_file = ['wm.nii.gz', 'csf.nii.gz']
    wmcsf.inputs.erode = [2, 2] #int(np.ceil(slice_thickness))
    wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), wmcsf, 'in_file')

    # Now transform the wm and csf masks to 1st volume of 1st run
    wmcsftransform = pe.MapNode(fs.ApplyVolTransform(inverse=True,
                                                     interp='nearest'),
                                iterfield=['target_file'],
                                name='wmcsftransform')
    wmcsftransform.inputs.subjects_dir = subjects_dir
    wf.connect(extractref, 'roi_file', wmcsftransform, 'source_file')
    wf.connect(fs_register, ('out_reg_file', pickfirst), wmcsftransform, 'reg_file')
    wf.connect(wmcsf, 'binary_file', wmcsftransform, 'target_file')

    # Transform the binarized aparc+aseg file to the 1st volume of 1st run space
    fs_voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True),
                                 iterfield = ['source_file', 'reg_file'],
                                 name='fs_transform')
    fs_voltransform.inputs.subjects_dir = subjects_dir
    wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file')
    wf.connect(fs_register, 'out_reg_file', fs_voltransform, 'reg_file')
    wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file')

    # Dilate the binarized mask by 1 voxel that is now in the EPI space
    fs_threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii'),
                               iterfield=['in_file'],
                               name='fs_threshold2')
    fs_threshold2.inputs.dilate = 1
    wf.connect(fs_voltransform, 'transformed_file', fs_threshold2, 'in_file')
    wf.connect(fs_threshold2, 'binary_file', outputnode, 'mask_file')
    
    # Use RapidART to detect motion/intensity outliers
    art = pe.MapNode(ra.ArtifactDetect(use_differences = [True, False],
                                       use_norm = True,
                                       zintensity_threshold = 3,
                                       norm_threshold = 1,
                                       bound_by_brainmask=True,
                                       mask_type = "file"),
                     iterfield=["realignment_parameters","realigned_files"],
                     name="art")
    if slice_times is not None:
        art.inputs.parameter_source = "NiPy"
    else:
        art.inputs.parameter_source = "FSL"
    wf.connect(motion_correct, 'par_file', art, 'realignment_parameters')
    wf.connect(motion_correct, 'out_file', art, 'realigned_files')
    wf.connect(fs_threshold2, ('binary_file', pickfirst), art, 'mask_file')
    wf.connect(art, 'norm_files', outputnode, 'artnorm_files')
    wf.connect(art, 'outlier_files', outputnode, 'artoutlier_files')
    wf.connect(art, 'displacement_files', outputnode, 'artdisplacement_files')

    # Compute motion regressors (save file with 1st and 2nd derivatives)
    motreg = pe.Node(util.Function(input_names=['motion_params', 'order',
                                                'derivatives'],
                                   output_names=['out_files'],
                                   function=motion_regressors,
                                   imports=imports),
                     name='getmotionregress')
    wf.connect(motion_correct, 'par_file', motreg, 'motion_params')
    wf.connect(motreg, 'out_files', outputnode, 'motion_parameters_plusDerivs')

    # Create a filter text file to remove motion (+ derivatives), art confounds,
    # and 1st, 2nd, and 3rd order legendre polynomials.
    createfilter1 = pe.Node(util.Function(input_names=['motion_params', 'comp_norm',
                                                       'outliers', 'detrend_poly'],
                                          output_names=['out_files'],
                                          function=build_filter1,
                                          imports=imports),
                            name='makemotionbasedfilter')
    createfilter1.inputs.detrend_poly = 3
    wf.connect(motreg, 'out_files', createfilter1, 'motion_params')
    wf.connect(art, 'norm_files', createfilter1, 'comp_norm')
    wf.connect(art, 'outlier_files', createfilter1, 'outliers')
    wf.connect(createfilter1, 'out_files', outputnode, 'motionandoutlier_noise_file')

    # Create a filter to remove noise components based on white matter and CSF
    createfilter2 = pe.MapNode(util.Function(input_names=['realigned_file', 'mask_file',
                                                          'num_components',
                                                          'extra_regressors'],
                                             output_names=['out_files'],
                                             function=extract_noise_components,
                                             imports=imports),
                               iterfield=['realigned_file', 'extra_regressors'],
                               name='makecompcorrfilter')
    createfilter2.inputs.num_components = num_components
    wf.connect(createfilter1, 'out_files', createfilter2, 'extra_regressors')
    wf.connect(motion_correct, 'out_file', createfilter2, 'realigned_file')
    wf.connect(wmcsftransform, 'transformed_file', createfilter2, 'mask_file')
    wf.connect(createfilter2, 'out_files', outputnode, 'noise_components')

    # Mask the functional runs with the extracted mask
    maskfunc = pe.MapNode(fsl.ImageMaths(suffix='_bet',
                                         op_string='-mas'),
                          iterfield=['in_file'],
                          name = 'maskfunc')
    wf.connect(motion_correct, 'out_file', maskfunc, 'in_file')
    wf.connect(fs_threshold2, ('binary_file', pickfirst), maskfunc, 'in_file2')
    
    # Smooth each run using SUSAn with the brightness threshold set to 75%
    # of the median value for each run and a mask constituting the mean functional
    smooth_median = pe.MapNode(fsl.ImageStats(op_string='-k %s -p 50'),
                               iterfield = ['in_file'],
                               name='smooth_median')
    wf.connect(maskfunc, 'out_file', smooth_median, 'in_file')
    wf.connect(fs_threshold2, ('binary_file', pickfirst), smooth_median, 'mask_file')
    
    smooth_meanfunc = pe.MapNode(fsl.ImageMaths(op_string='-Tmean',
                                                suffix='_mean'),
                                 iterfield=['in_file'],
                                 name='smooth_meanfunc')
    wf.connect(maskfunc, 'out_file', smooth_meanfunc, 'in_file')

    smooth_merge = pe.Node(util.Merge(2, axis='hstack'),
                           name='smooth_merge')
    wf.connect(smooth_meanfunc, 'out_file', smooth_merge, 'in1')
    wf.connect(smooth_median, 'out_stat', smooth_merge, 'in2')

    smooth = pe.MapNode(fsl.SUSAN(),
                        iterfield=['in_file', 'brightness_threshold', 'usans'],
                        name='smooth')
    smooth.inputs.fwhm=fwhm
    wf.connect(maskfunc, 'out_file', smooth, 'in_file')
    wf.connect(smooth_median, ('out_stat', getbtthresh), smooth, 'brightness_threshold')
    wf.connect(smooth_merge, ('out', getusans), smooth, 'usans')
    
    # Mask the smoothed data with the dilated mask
    maskfunc2 = pe.MapNode(fsl.ImageMaths(suffix='_mask',
                                          op_string='-mas'),
                           iterfield=['in_file'],
                           name='maskfunc2')
    wf.connect(smooth, 'smoothed_file', maskfunc2, 'in_file')
    wf.connect(fs_threshold2, ('binary_file', pickfirst), maskfunc2, 'in_file2')
    wf.connect(maskfunc2, 'out_file', outputnode, 'smoothed_files')

    # Band-pass filter the timeseries
    if use_fsl_bp == 'True':
        determine_bp_sigmas = pe.Node(util.Function(input_names=['tr',
                                                                 'highpass_freq',
                                                                 'lowpass_freq'],
                                                    output_names = ['out_sigmas'],
                                                    function=calc_fslbp_sigmas),
                                      name='determine_bp_sigmas')
        determine_bp_sigmas.inputs.tr = float(TR)
        determine_bp_sigmas.inputs.highpass_freq = float(highpass_frequency)
        determine_bp_sigmas.inputs.lowpass_freq = float(lowpass_frequency)

        bandpass = pe.MapNode(fsl.ImageMaths(suffix='_tempfilt'),
                              iterfield=["in_file"],
                              name="bandpass")
        wf.connect(determine_bp_sigmas, ('out_sigmas', highpass_operand), bandpass, 'op_string')
        wf.connect(maskfunc2, 'out_file', bandpass, 'in_file')
        wf.connect(bandpass, 'out_file', outputnode, 'bandpassed_files')
    else:
        bandpass = pe.Node(util.Function(input_names=['files',
                                                      'lowpass_freq',
                                                      'highpass_freq',
                                                      'fs'],
                                         output_names=['out_files'],
                                         function=bandpass_filter,
                                         imports=imports),
                           name='bandpass')
        bandpass.inputs.fs = 1./TR
        if highpass_frequency < 0:
            bandpass.inputs.highpass_freq = -1
        else:
            bandpass.inputs.highpass_freq = highpass_frequency
        if lowpass_frequency < 0:
            bandpass.inputs.lowpass_freq = -1
        else:
            bandpass.inputs.lowpass_freq = lowpass_frequency
        wf.connect(maskfunc2, 'out_file', bandpass, 'files')
        wf.connect(bandpass, 'out_files', outputnode, 'bandpassed_files')

    # Save the relevant data into an output directory
    datasink = pe.Node(nio.DataSink(), name="datasink")
    datasink.inputs.base_directory = sink_directory
    datasink.inputs.container = subject_id
    wf.connect(outputnode, 'reference', datasink, 'ref')
    wf.connect(outputnode, 'motion_parameters', datasink, 'motion')
    wf.connect(outputnode, 'realigned_files', datasink, 'func.realigned')
    wf.connect(outputnode, 'motion_plots', datasink, 'motion.@plots')
    wf.connect(outputnode, 'mask_file', datasink, 'ref.@mask')
    wf.connect(outputnode, 'smoothed_files', datasink, 'func.smoothed_fullspectrum')
    wf.connect(outputnode, 'bandpassed_files', datasink, 'func.smoothed_bandpassed')
    wf.connect(outputnode, 'reg_file', datasink, 'bbreg.@reg')
    wf.connect(outputnode, 'reg_cost', datasink, 'bbreg.@cost')
    wf.connect(outputnode, 'reg_fsl_file', datasink, 'bbreg.@regfsl')
    wf.connect(outputnode, 'artnorm_files', datasink, 'art.@norm_files')
    wf.connect(outputnode, 'artoutlier_files', datasink, 'art.@outlier_files')
    wf.connect(outputnode, 'artdisplacement_files', datasink, 'art.@displacement_files')
    wf.connect(outputnode, 'motion_parameters_plusDerivs', datasink, 'noise.@motionplusDerivs')
    wf.connect(outputnode, 'motionandoutlier_noise_file', datasink, 'noise.@motionplusoutliers')
    wf.connect(outputnode, 'noise_components', datasink, 'compcor')
    wf.connect(outputnode, 'tsnr_file', datasink, 'tsnr')    

    return wf
Example #19
0
    # Tip 11: Add any arguments to the Node as a field in the object (e.g., coreg). Nipype doesn't seem to register inputs in the Node definition... or at least the _report.rst makes it seem like the arguments may not be communicated.
    # Tip 12: Look at the _report/_report.rst and pyscript_{node_variable} to figure out what ran.

    import nipype.interfaces.spm as spm
    import nipype.algorithms.rapidart as ra  # artifact detection
    # SPM Realign (Estimate & Reslice - Reslice only the mean image)
    realign = Node(interface=spm.Realign(), name="realign")
    realign.inputs.jobtype = 'estwrite'
    realign.inputs.register_to_mean = True
    realign.inputs.write_which = [
        0, 1
    ]  # first field is for "reslice all"; 2nd is "reslice mean"

    # ART evaluation of realignment parameters
    art = Node(interface=ra.ArtifactDetect(), name='art')
    art.inputs.norm_threshold = 1
    art.inputs.zintensity_threshold = 5
    art.inputs.mask_type = 'spm_global'
    art.inputs.parameter_source = 'SPM'
    art.inputs.use_differences = [
        True, False
    ]  # Reflects use difference for motion, not intensity
    art.inputs.use_norm = True

    # SPM Coregister (Estimate Only)
    coreg = Node(interface=spm.Coregister(), name="coregister")
    coreg.inputs.jobtype = 'estimate'

    # SPM Normalise (Estimate & Reslice)
    norm12 = Node(interface=spm.Normalize12(), name="normalize")
Example #20
0
    (selectfiles, fix_header_wmmask, [('wm_mask', 'data_file'),
                                      ('unwarped_file', 'header_file')]),
])

# merge images into list
masklist = Node(util.Merge(2), name='masklist')
preproc_nuisance_regress.connect([
    (fix_header_csfmask, masklist, [('out_file', 'in1')]),
    (fix_header_wmmask, masklist, [('out_file', 'in2')]),
])

# perform artefact detection
artefact = Node(ra.ArtifactDetect(save_plot=True,
                                  use_norm=True,
                                  parameter_source='NiPy',
                                  mask_type='file',
                                  norm_threshold=1,
                                  zintensity_threshold=3,
                                  use_differences=[True, False]),
                name='artefact')

preproc_nuisance_regress.connect([
    (selectfiles, artefact, [('unwarped_file', 'realigned_files'),
                             ('slicemoco_par_file', 'realignment_parameters')
                             ]),
    (selectfiles, artefact, [('gm_mask', 'mask_file')]),
])

# calculate motion regressors

motreg = Node(util.Function(
Example #21
0
preproc_wf.connect(fs_voltransform, 'transformed_file', fs_threshold2,
                   'in_file')
preproc_wf.connect(fs_threshold2, 'binary_file', outputspec, 'mask_file')

# Mask the functional runs with the extracted mask
maskfunc = pe.MapNode(fsl.ImageMaths(suffix='_bet', op_string='-mas'),
                      iterfield=['in_file'],
                      name='maskfunc')
preproc_wf.connect(motion_correct, 'out_file', maskfunc, 'in_file')
preproc_wf.connect(fs_threshold2, ('binary_file', pickfirst), maskfunc,
                   'in_file2')

# Use RapidART to detect motion/intensity outliers
art = pe.MapNode(ra.ArtifactDetect(use_differences=[True, False],
                                   use_norm=True,
                                   zintensity_threshold=3,
                                   norm_threshold=1,
                                   bound_by_brainmask=True,
                                   mask_type='file'),
                 iterfield=['realignment_parameters', 'realigned_files'],
                 name='art')
art.inputs.parameter_source = 'NiPy'
preproc_wf.connect(motion_correct, 'par_file', art, 'realignment_parameters')
preproc_wf.connect(motion_correct, 'out_file', art, 'realigned_files')
preproc_wf.connect(fs_threshold2, ('binary_file', pickfirst), art, 'mask_file')
preproc_wf.connect(art, 'norm_files', outputspec, 'artnorm_files')
preproc_wf.connect(art, 'outlier_files', outputspec, 'artoutlier_files')
preproc_wf.connect(art, 'displacement_files', outputspec,
                   'artdisplacement_files')

# Compute motion regressors (save file with 1st and 2nd derivatives)
motreg = pe.Node(util.Function(
        columns=['trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z'],
        header=False, index=False)
    return os.path.abspath('mcparams.tsv')

mcparams = pe.Node(niu.Function(input_names=['confounds_file'],
                                output_names=['realignment_parameters'],
                                     function=get_mcparams),
                        'mcparams')


# Rapidart node

# In[15]:


art = pe.Node(ra.ArtifactDetect(), 'art')
art.inputs.parameter_source = 'SPM'
art.inputs.norm_threshold = 1
art.inputs.use_differences = [True, False]
art.inputs.zintensity_threshold = 3
art.inputs.mask_type = 'file'


# **ModelGrabber:** Grab model specification info (util)

# In[16]:
def ModelGrabber(contrasts_file, events_file, confounds_file):

    from os import environ
    import numpy as np
    import pandas as pd
Example #23
0
def analyze_openfmri_dataset(data_dir, subject=None, model_id=None,
                             task_id=None, output_dir=None, subj_prefix='*',
                             hpcutoff=120., use_derivatives=True,
                             fwhm=6.0, subjects_dir=None, target=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()
    if subjects_dir:
        registration = create_fs_reg_workflow()
    else:
        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
    """

    contrast_file = os.path.join(data_dir, 'models', 'model%03d' % model_id,
                                 'task_contrasts.txt')
    has_contrast = os.path.exists(contrast_file)
    if has_contrast:
        datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run_id',
                                                   'task_id', 'model_id'],
                                         outfields=['anat', 'bold', 'behav',
                                                    'contrasts']),
                         name='datasource')
    else:
        datasource = pe.Node(nio.DataGrabber(infields=['subject_id', 'run_id',
                                                   'task_id', 'model_id'],
                                         outfields=['anat', 'bold', 'behav']),
                         name='datasource')
    datasource.inputs.base_directory = data_dir
    datasource.inputs.template = '*'

    if has_contrast:
        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']]}
    else:
        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')}
        datasource.inputs.template_args = {'anat': [['subject_id']],
                                       'bold': [['subject_id', 'task_id']],
                                       'behav': [['subject_id', 'model_id',
                                                  'task_id', 'run_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
        import os
        contrast_def = []
        if os.path.exists(contrast_file):
            with open(contrast_file, 'rt') as fp:
                contrast_def.extend([np.array(row.split()) for row in fp.readlines() if row.strip()])
        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, run_id, conds):
        from nipype.external import six
        import numpy as np
        num_conds = len(conds)
        if isinstance(behav, six.string_types):
            behav = [behav]
        behav_array = np.array(behav).flatten()
        num_elements = behav_array.shape[0]
        return behav_array.reshape(num_elements/num_conds, num_conds).tolist()

    reshape_behav = pe.Node(niu.Function(input_names=['behav', 'run_id', 'conds'],
                                       output_names=['behav'],
                                       function=check_behav_list),
                          name='reshape_behav')

    wf.connect(subjinfo, 'TR', modelspec, 'time_repetition')
    wf.connect(datasource, 'behav', reshape_behav, 'behav')
    wf.connect(subjinfo, 'run_id', reshape_behav, 'run_id')
    wf.connect(subjinfo, 'conds', reshape_behav, 'conds')
    wf.connect(reshape_behav, 'behav', modelspec, 'event_files')

    wf.connect(subjinfo, 'TR', modelfit, 'inputspec.interscan_interval')
    wf.connect(subjinfo, 'conds', contrastgen, 'conds')
    if has_contrast:
        wf.connect(datasource, 'contrasts', contrastgen, 'contrast_file')
    else:
        contrastgen.inputs.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')])
                ])

    # Comute TSNR on realigned data regressing polynomials upto order 2
    tsnr = MapNode(TSNR(regress_poly=2), iterfield=['in_file'], name='tsnr')
    wf.connect(preproc, "outputspec.realigned_files", tsnr, "in_file")

    # Compute the median image across runs
    calc_median = Node(Function(input_names=['in_files'],
                                output_names=['median_file'],
                                function=median,
                                imports=imports),
                       name='median')
    wf.connect(tsnr, 'detrended_file', calc_median, 'in_files')

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

    def sort_copes(copes, varcopes, contrasts):
        import numpy as np
        if not isinstance(copes, list):
            copes = [copes]
            varcopes = [varcopes]
        num_copes = len(contrasts)
        n_runs = len(copes)
        all_copes = np.array(copes).flatten()
        all_varcopes = np.array(varcopes).flatten()
        outcopes = all_copes.reshape(len(all_copes)/num_copes, num_copes).T.tolist()
        outvarcopes = all_varcopes.reshape(len(all_varcopes)/num_copes, num_copes).T.tolist()
        return outcopes, outvarcopes, n_runs

    cope_sorter = pe.Node(niu.Function(input_names=['copes', 'varcopes',
                                                    'contrasts'],
                                       output_names=['copes', 'varcopes',
                                                     'n_runs'],
                                       function=sort_copes),
                          name='cope_sorter')

    pickfirst = lambda x: x[0]

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

    wf.connect(calc_median, 'median_file', registration, 'inputspec.mean_image')
    if subjects_dir:
        wf.connect(infosource, 'subject_id', registration, 'inputspec.subject_id')
        registration.inputs.inputspec.subjects_dir = subjects_dir
        registration.inputs.inputspec.target_image = fsl.Info.standard_image('MNI152_T1_2mm_brain.nii.gz')
        if target:
            registration.inputs.inputspec.target_image = target
    else:
        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')

    if subjects_dir:
        get_roi_mean = pe.MapNode(fs.SegStats(default_color_table=True),
                                  iterfield=['in_file'], name='get_aparc_means')
        get_roi_mean.inputs.avgwf_txt_file = True
        wf.connect(fixed_fx.get_node('outputspec'), 'copes', get_roi_mean, 'in_file')
        wf.connect(registration, 'outputspec.aparc', get_roi_mean, 'segmentation_file')

        get_roi_tsnr = pe.MapNode(fs.SegStats(default_color_table=True),
                                  iterfield=['in_file'], name='get_aparc_tsnr')
        get_roi_tsnr.inputs.avgwf_txt_file = True
        wf.connect(tsnr, 'tsnr_file', get_roi_tsnr, 'in_file')
        wf.connect(registration, 'outputspec.aparc', get_roi_tsnr, 'segmentation_file')

    """
    Connect to a datasink
    """

    def get_subs(subject_id, conds, run_id, 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)))
            subs.append(('_warpall%d/cope1_trans.' % i,
                         'cope%02d.' % (i + 1)))
            subs.append(('_warpall%d/varcope1_trans.' % (len(conds) + i),
                         'varcope%02d.' % (i + 1)))
            subs.append(('_warpall%d/zstat1_trans.' % (2 * len(conds) + i),
                         'zstat%02d.' % (i + 1)))
            subs.append(('__get_aparc_means%d/' % i, '/cope%02d_' % (i + 1)))

        for i, run_num in enumerate(run_id):
            subs.append(('__get_aparc_tsnr%d/' % i, '/run%02d_' % run_num))
            subs.append(('__art%d/' % i, '/run%02d_' % run_num))
            subs.append(('__dilatemask%d/' % i, '/run%02d_' % run_num))
            subs.append(('__realign%d/' % i, '/run%02d_' % run_num))
            subs.append(('__modelgen%d/' % i, '/run%02d_' % run_num))
        subs.append(('/model%03d/task%03d/' % (model_id, task_id), '/'))
        subs.append(('/model%03d/task%03d_' % (model_id, task_id), '/'))
        subs.append(('_bold_dtype_mcf_bet_thresh_dil', '_mask'))
        subs.append(('_output_warped_image', '_anat2target'))
        subs.append(('median_flirt_brain_mask', 'median_brain_mask'))
        subs.append(('median_bbreg_brain_mask', 'median_brain_mask'))
        return subs

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

    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([(modelfit.get_node('modelgen'), datasink,
                                 [('design_cov', 'qa.model'),
                                  ('design_image', 'qa.model.@matrix_image'),
                                  ('design_file', 'qa.model.@matrix'),
                                 ])])
    wf.connect([(preproc, datasink, [('outputspec.motion_parameters',
                                      'qa.motion'),
                                     ('outputspec.motion_plots',
                                      'qa.motion.plots'),
                                     ('outputspec.mask', 'qa.mask')])])
    wf.connect(registration, 'outputspec.mean2anat_mask', datasink, 'qa.mask.mean2anat')
    wf.connect(art, 'norm_files', datasink, 'qa.art.@norm')
    wf.connect(art, 'intensity_files', datasink, 'qa.art.@intensity')
    wf.connect(art, 'outlier_files', datasink, 'qa.art.@outlier_files')
    wf.connect(registration, 'outputspec.anat2target', datasink, 'qa.anat2target')
    wf.connect(tsnr, 'tsnr_file', datasink, 'qa.tsnr.@map')
    if subjects_dir:
        wf.connect(registration, 'outputspec.min_cost_file', datasink, 'qa.mincost')
        wf.connect([(get_roi_tsnr, datasink, [('avgwf_txt_file', 'qa.tsnr'),
                                              ('summary_file', 'qa.tsnr.@summary')])])
        wf.connect([(get_roi_mean, datasink, [('avgwf_txt_file', 'copes.roi'),
                                              ('summary_file', 'copes.roi.@summary')])])
    wf.connect([(splitfunc, datasink,
                 [('copes', 'copes.mni'),
                  ('varcopes', 'varcopes.mni'),
                  ('zstats', 'zstats.mni'),
                  ])])
    wf.connect(calc_median, 'median_file', datasink, 'mean')
    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
    """

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

    datasink.inputs.base_directory = output_dir
    return wf
def create_spm_preproc(c, name='preproc'):
    """
"""

    from nipype.workflows.smri.freesurfer.utils import create_getmask_flow
    import nipype.algorithms.rapidart as ra
    import nipype.interfaces.spm as spm
    import nipype.interfaces.utility as niu
    import nipype.pipeline.engine as pe
    import nipype.interfaces.io as nio
    import nipype.interfaces.freesurfer as fs

    workflow = pe.Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold',
        'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder',
        'parameters', 'node', 'csf_prob', 'wm_prob', 'gm_prob'
    ]),
                        name='inputspec')

    poplist = lambda x: x.pop()

    sym_func = pe.Node(niu.Function(input_names=['in_file'],
                                    output_names=['out_link'],
                                    function=do_symlink),
                       name='func_symlink')

    # REALIGN

    realign = pe.Node(niu.Function(
        input_names=[
            'node', 'in_file', 'tr', 'do_slicetime', 'sliceorder', 'parameters'
        ],
        output_names=['out_file', 'par_file', 'parameter_source'],
        function=mod_realign),
                      name="mod_realign")
    workflow.connect(inputnode, 'parameters', realign, 'parameters')
    workflow.connect(inputnode, 'functionals', realign, 'in_file')
    workflow.connect(inputnode, 'tr', realign, 'tr')
    workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime')
    workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder')
    workflow.connect(inputnode, 'node', realign, 'node')

    # TAKE MEAN IMAGE

    mean = art_mean_workflow()
    workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files')
    workflow.connect(realign, 'par_file', mean,
                     'inputspec.realignment_parameters')
    workflow.connect(realign, 'parameter_source', mean,
                     'inputspec.parameter_source')

    # CREATE BRAIN MASK

    maskflow = create_getmask_flow()
    workflow.connect([(inputnode, maskflow,
                       [('subject_id', 'inputspec.subject_id'),
                        ('subjects_dir', 'inputspec.subjects_dir')])])
    maskflow.inputs.inputspec.contrast_type = 't2'
    workflow.connect(mean, 'outputspec.mean_image', maskflow,
                     'inputspec.source_file')

    # SEGMENT

    segment = pe.Node(spm.Segment(csf_output_type=[True, True, False],
                                  gm_output_type=[True, True, False],
                                  wm_output_type=[True, True, False]),
                      name='segment')
    mergefunc = lambda in1, in2, in3: [in1, in2, in3]

    merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'],
                                 output_names=['out'],
                                 function=mergefunc),
                    name='merge')
    workflow.connect(inputnode, 'csf_prob', merge, 'in3')
    workflow.connect(inputnode, 'wm_prob', merge, 'in2')
    workflow.connect(inputnode, 'gm_prob', merge, 'in1')

    sym_prob = sym_func
    workflow.connect(merge, 'out', sym_prob, 'in_file')
    workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps')

    xform_mask = pe.Node(fs.ApplyVolTransform(fs_target=True),
                         name='transform_mask')
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_mask,
                     'reg_file')
    workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), xform_mask,
                     'source_file')
    workflow.connect(xform_mask, "transformed_file", segment, 'mask_image')

    fssource = maskflow.get_node('fssource')
    convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'),
                          name='convert2nii')
    workflow.connect(fssource, 'brain', convert2nii, 'in_file')
    workflow.connect(convert2nii, 'out_file', segment, 'data')

    # NORMALIZE

    normalize = pe.MapNode(spm.Normalize(jobtype='write'),
                           name='normalize',
                           iterfield=['apply_to_files'])
    normalize_struct = normalize.clone('normalize_struct')
    normalize_mask = normalize.clone('normalize_mask')

    workflow.connect(segment, 'transformation_mat', normalize,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_mask,
                     'parameter_file')
    workflow.connect(segment, 'transformation_mat', normalize_struct,
                     'parameter_file')
    workflow.connect(convert2nii, 'out_file', normalize_struct,
                     'apply_to_files')
    workflow.connect(xform_mask, "transformed_file", normalize_mask,
                     'apply_to_files')

    xform_image = pe.MapNode(fs.ApplyVolTransform(fs_target=True),
                             name='xform_image',
                             iterfield=['source_file'])
    workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_image,
                     'reg_file')
    workflow.connect(realign, 'out_file', xform_image, "source_file")
    workflow.connect(xform_image, "transformed_file", normalize,
                     "apply_to_files")

    #SMOOTH

    smooth = pe.Node(spm.Smooth(), name='smooth')

    workflow.connect(inputnode, 'fwhm', smooth, 'fwhm')
    workflow.connect(normalize, 'normalized_files', smooth, 'in_files')

    # ART

    artdetect = pe.Node(ra.ArtifactDetect(mask_type='file',
                                          use_differences=[True, False],
                                          use_norm=True,
                                          save_plot=True),
                        name='artdetect')
    workflow.connect(realign, 'parameter_source', artdetect,
                     'parameter_source')
    workflow.connect([(inputnode, artdetect,
                       [('norm_threshold', 'norm_threshold'),
                        ('zintensity_threshold', 'zintensity_threshold')])])
    workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'),
                                            ('par_file',
                                             'realignment_parameters')])])
    workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect,
                     'mask_file')

    # OUTPUTS

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        "realignment_parameters", "smoothed_files", "mask_file", "mean_image",
        "reg_file", "reg_cost", 'outlier_files', 'outlier_stats',
        'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm',
        'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct',
        'normalization_parameters', 'reverse_normalize_parameters'
    ]),
                         name="outputspec")
    workflow.connect([
        (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]),
        (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]),
        (realign, outputnode, [('par_file', 'realignment_parameters')]),
        (smooth, outputnode, [('smoothed_files', 'smoothed_files')]),
        (artdetect, outputnode, [('outlier_files', 'outlier_files'),
                                 ('statistic_files', 'outlier_stats'),
                                 ('plot_files', 'outlier_plots'),
                                 ('norm_files', 'norm_components')])
    ])
    workflow.connect(normalize_mask, "normalized_files", outputnode,
                     "mask_file")
    workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf')
    workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm')
    workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm')
    workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf')
    workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm')
    workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm')
    workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean')
    workflow.connect(normalize_struct, 'normalized_files', outputnode,
                     'normalized_struct')
    workflow.connect(segment, 'transformation_mat', outputnode,
                     'normalization_parameters')
    workflow.connect(segment, 'inverse_transformation_mat', outputnode,
                     'reverse_normalize_parameters')

    # CONNECT TO CONFIG

    workflow.inputs.inputspec.fwhm = c.fwhm
    workflow.inputs.inputspec.subjects_dir = c.surf_dir
    workflow.inputs.inputspec.norm_threshold = c.norm_thresh
    workflow.inputs.inputspec.zintensity_threshold = c.z_thresh
    workflow.inputs.inputspec.node = c.motion_correct_node
    workflow.inputs.inputspec.tr = c.TR
    workflow.inputs.inputspec.do_slicetime = c.do_slicetiming
    workflow.inputs.inputspec.sliceorder = c.SliceOrder
    workflow.inputs.inputspec.csf_prob = c.csf_prob
    workflow.inputs.inputspec.gm_prob = c.grey_prob
    workflow.inputs.inputspec.wm_prob = c.white_prob
    workflow.inputs.inputspec.parameters = {"order": c.order}
    workflow.base_dir = c.working_dir
    workflow.config = {'execution': {'crashdump_dir': c.crash_dir}}

    datagrabber = get_dataflow(c)

    workflow.connect(datagrabber, 'func', inputnode, 'functionals')

    infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']),
                         name='subject_names')
    if not c.test_mode:
        infosource.iterables = ('subject_id', c.subjects)
    else:
        infosource.iterables = ('subject_id', c.subjects[:1])

    workflow.connect(infosource, 'subject_id', inputnode, 'subject_id')
    workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id')
    sub = lambda x: [('_subject_id_%s' % x, '')]

    sinker = pe.Node(nio.DataSink(), name='sinker')
    workflow.connect(infosource, 'subject_id', sinker, 'container')
    workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions')
    sinker.inputs.base_directory = c.sink_dir
    outputspec = workflow.get_node('outputspec')
    workflow.connect(outputspec, 'realignment_parameters', sinker,
                     'spm_preproc.realignment_parameters')
    workflow.connect(outputspec, 'smoothed_files', sinker,
                     'spm_preproc.smoothed_outputs')
    workflow.connect(outputspec, 'outlier_files', sinker,
                     'spm_preproc.art.@outlier_files')
    workflow.connect(outputspec, 'outlier_stats', sinker,
                     'spm_preproc.art.@outlier_stats')
    workflow.connect(outputspec, 'outlier_plots', sinker,
                     'spm_preproc.art.@outlier_plots')
    workflow.connect(outputspec, 'norm_components', sinker,
                     'spm_preproc.art.@norm')
    workflow.connect(outputspec, 'reg_file', sinker,
                     'spm_preproc.bbreg.@reg_file')
    workflow.connect(outputspec, 'reg_cost', sinker,
                     'spm_preproc.bbreg.@reg_cost')
    workflow.connect(outputspec, 'mask_file', sinker,
                     'spm_preproc.mask.@mask_file')
    workflow.connect(outputspec, 'mod_csf', sinker,
                     'spm_preproc.segment.mod.@csf')
    workflow.connect(outputspec, 'mod_wm', sinker,
                     'spm_preproc.segment.mod.@wm')
    workflow.connect(outputspec, 'mod_gm', sinker,
                     'spm_preproc.segment.mod.@gm')
    workflow.connect(outputspec, 'unmod_csf', sinker,
                     'spm_preproc.segment.unmod.@csf')
    workflow.connect(outputspec, 'unmod_wm', sinker,
                     'spm_preproc.segment.unmod.@wm')
    workflow.connect(outputspec, 'unmod_gm', sinker,
                     'spm_preproc.segment.unmod.@gm')
    workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean')
    workflow.connect(outputspec, 'normalized_struct', sinker,
                     'spm_preproc.normalized_struct')
    workflow.connect(outputspec, 'normalization_parameters', sinker,
                     'spm_preproc.normalization_parameters.@forward')
    workflow.connect(outputspec, 'reverse_normalize_parameters', sinker,
                     'spm_preproc.normalization_parameters.@reverse')

    return workflow
Example #25
0
"""

preproc = pe.Workflow(name='preproc')
"""Use :class:`nipype.interfaces.spm.Realign` for motion correction
and register all images to the mean image.
"""

realign = pe.Node(interface=spm.Realign(), name="realign")
realign.inputs.register_to_mean = True
"""Use :class:`nipype.algorithms.rapidart` to determine which of the
images in the functional series are outliers based on deviations in
intensity or movement.
"""

art = pe.Node(interface=ra.ArtifactDetect(), name="art")
art.inputs.use_differences = [True, False]
art.inputs.use_norm = True
art.inputs.norm_threshold = 1
art.inputs.zintensity_threshold = 3
art.inputs.mask_type = 'file'
art.inputs.parameter_source = 'SPM'
"""Skull strip structural images using
:class:`nipype.interfaces.fsl.BET`.
"""

skullstrip = pe.Node(interface=fsl.BET(), name="skullstrip")
skullstrip.inputs.mask = True
"""Use :class:`nipype.interfaces.spm.Coregister` to perform a rigid
body registration of the functional data to the structural data.
"""
Example #26
0
def create_art_workflow(name="art", make_movie=True):

    # Define the workflow inputs
    inputnode = pe.Node(util.IdentityInterface(fields=[
        "raw_timeseries", "realigned_timeseries", "mask_file",
        "realignment_parameters"
    ]),
                        name="inputs")

    # Use RapidART to detect motion/intensity outliers
    art = pe.MapNode(
        ra.ArtifactDetect(use_differences=[True, False],
                          use_norm=True,
                          zintensity_threshold=3,
                          norm_threshold=1,
                          parameter_source="FSL",
                          mask_type="file"),
        iterfield=["realignment_parameters", "realigned_files", "mask_file"],
        name="art")

    # Plot a timeseries of the global mean intensity
    art_plot_inputs = ["intensity_file", "outlier_file"]
    plotmean = pe.MapNode(util.Function(input_names=art_plot_inputs,
                                        output_names="intensity_plot",
                                        function=write_art_plot),
                          iterfield=art_plot_inputs,
                          name="plotmean")

    # Use our very own ts_movie script to generate a movie of the timeseries
    if make_movie:
        tsmovie = pe.MapNode(TimeSeriesMovie(ref_type="mean"),
                             iterfield=["in_file", "plot_file"],
                             name="tsmovie")

        # Rename the outputs
        moviename = pe.MapNode(
            util.Rename(format_string="timeseries_movie.gif"),
            iterfield=["in_file"],
            name="moviename")

    outliername = pe.MapNode(util.Rename(format_string="outlier_volumes.txt"),
                             iterfield=["in_file"],
                             name="outliername")

    # Define the workflow outputs
    out_fields = ["outlier_volumes", "intensity_plot"]
    if make_movie:
        out_fields.append("timeseries_movie")

    outputnode = pe.Node(util.IdentityInterface(fields=out_fields),
                         name="outputs")

    # Define and connect the workflow
    artifact = pe.Workflow(name=name)
    artifact.connect([
        (inputnode, art, [("realignment_parameters", "realignment_parameters"),
                          ("realigned_timeseries", "realigned_files"),
                          ("mask_file", "mask_file")]),
        (art, plotmean, [("intensity_files", "intensity_file"),
                         ("outlier_files", "outlier_file")]),
        (art, outliername, [("outlier_files", "in_file")]),
        (outliername, outputnode, [("out_file", "outlier_volumes")]),
        (plotmean, outputnode, [("intensity_plot", "intensity_plot")]),
    ])

    if make_movie:
        artifact.connect([
            (inputnode, tsmovie, [("raw_timeseries", "in_file")]),
            (art, tsmovie, [("intensity_files", "plot_file")]),
            (tsmovie, moviename, [("out_file", "in_file")]),
            (moviename, outputnode, [("out_file", "timeseries_movie")]),
        ])

    return artifact
Example #27
0
                             iterfield = ['in_file'])
motion_correct.inputs.in_file = func_files
psb6351_wf.connect(extractref, 'roi_file', motion_correct, 'ref_file')
psb6351_wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters')
psb6351_wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files')
'''

###############################
# ADD RAPIDART DETECTION HERE #
###############################
# Evaluate the number of outliers that are detected
# when using zintensity_thresholds of 1, 2, 3, 4
# and when using norm_threshold of 2, 1, 0.5, 0.2
###############################

AD = pe.MapNode(rapidart.ArtifactDetect(),
                iterfield=['realigned_files', 'realignment_parameters'],
                name='AD')
AD.inputs.mask_type = 'spm_global'
AD.inputs.norm_threshold = 2.0
AD.inputs.parameter_source = 'AFNI'
#AD.inputs.realigned_files = 'motion_func'
#AD.inputs.realignment_parameters = 'motion_par'
AD.inputs.zintensity_threshold = 1.0
AD.inputs.global_threshold = 9.0
#AD.inputs.use_norm = 'TRUE'

psb6351_wf.connect(volreg, 'out_file', AD, 'realigned_files')
psb6351_wf.connect(volreg, 'oned_file', AD, 'realignment_parameters')

# Below is the command that runs AFNI's 3dTshift command
Example #28
0
def test_ad_init():
    ad = ra.ArtifactDetect(use_differences=[True, False])
    yield assert_true, ad.inputs.use_differences[0]
    yield assert_false, ad.inputs.use_differences[1]
Example #29
0
"""

preproc = pe.Workflow(name='preproc')
"""Use :class:`nipype.interfaces.spm.Realign` for motion correction
and register all images to the mean image.
"""

realign = pe.Node(spm.Realign(), name="realign")
realign.inputs.register_to_mean = True
"""Use :class:`nipype.algorithms.rapidart` to determine which of the
images in the functional series are outliers based on deviations in
intensity or movement.
"""

art = pe.Node(ra.ArtifactDetect(), name="art")
art.inputs.use_differences = [True, False]
art.inputs.use_norm = True
art.inputs.norm_threshold = 1
art.inputs.zintensity_threshold = 3
art.inputs.mask_type = 'file'
art.inputs.parameter_source = 'SPM'
"""Skull strip structural images using
:class:`nipype.interfaces.fsl.BET`.
"""

skullstrip = pe.Node(fsl.BET(), name="skullstrip")
skullstrip.inputs.mask = True
"""Use :class:`nipype.interfaces.spm.Coregister` to perform a rigid
body registration of the functional data to the structural data.
"""
Example #30
0
def create_workflow():
    featpreproc = pe.Workflow(name="featpreproc")

    featpreproc.base_dir = os.path.join(ds_root, 'workingdirs')

    # ===================================================================
    #                  _____                   _
    #                 |_   _|                 | |
    #                   | |  _ __  _ __  _   _| |_
    #                   | | | '_ \| '_ \| | | | __|
    #                  _| |_| | | | |_) | |_| | |_
    #                 |_____|_| |_| .__/ \__,_|\__|
    #                             | |
    #                             |_|
    # ===================================================================

    # ------------------ Specify variables
    inputnode = pe.Node(
        niu.IdentityInterface(fields=[
            'funcs',
            'subject_id',
            'session_id',
            'fwhm',  # smoothing
            'highpass'
        ]),
        name="inputspec")

    # SelectFiles
    templates = {
        'ref_manual_fmapmask':  # was: manual_fmapmask
        'derivatives/manual-masks/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_magnitude1_res-1x1x1_manualmask.nii.gz',

        'ref_fmap_magnitude':
        'derivatives/manual-masks/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_magnitude1_res-1x1x1_reference.nii.gz',

        'ref_fmap_phasediff':
        'derivatives/resampled-isotropic-1mm/sub-eddy/ses-20170511/fmap/'
            'sub-eddy_ses-20170511_phasediff_res-1x1x1_preproc'
            '.nii.gz',

        # 'manualweights':
        # 'manual-masks/sub-eddy/ses-20170511/func/'
        #     'sub-eddy_ses-20170511_task-curvetracing_run-01_frame-50_bold'
        #     '_res-1x1x1_manualweights.nii.gz',

        'ref_func':  # was: manualmask_func_ref
        'derivatives/manual-masks/sub-eddy/ses-20170607/func/'
            'sub-eddy_ses-20170607_task-RestingPRF_run-02_bold_'
            'res-1x1x1_fnirt_reference.nii.gz',

        'ref_funcmask':  # was: manualmask
        'derivatives/manual-masks/sub-eddy/ses-20170607/func/'
            'sub-eddy_ses-20170607_task-RestingPRF_run-02_bold_'
            'res-1x1x1_fnirt_mask.nii.gz',

        'ref_t1':
        'derivatives/manual-masks/sub-eddy/ses-20170511/anat/'
            'sub-eddy_ses-20170511_T1w_res-1x1x1_reference.nii.gz',

        'ref_t1mask':
        'derivatives/manual-masks/sub-eddy/ses-20170511/anat/'
            'sub-eddy_ses-20170511_T1w_res-1x1x1_manualmask.nii.gz',

        # 'funcs':
        # 'resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/func/'
        #     # 'sub-{subject_id}_ses-{session_id}*_bold_res-1x1x1_preproc'
        #     'sub-{subject_id}_ses-{session_id}*run-01_bold_res-1x1x1_preproc'
        #     # '.nii.gz',
        #     '_nvol10.nii.gz',

        'fmap_phasediff':
        'derivatives/resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/fmap/'
            'sub-{subject_id}_ses-{session_id}_phasediff_res-1x1x1_preproc'
            '.nii.gz',

        'fmap_magnitude':
        'derivatives/resampled-isotropic-1mm/sub-{subject_id}/ses-{session_id}/fmap/'
            'sub-{subject_id}_ses-{session_id}_magnitude1_res-1x1x1_preproc'
            '.nii.gz',

        # 'fmap_mask':
        # 'transformed-manual-fmap-mask/sub-{subject_id}/ses-{session_id}/fmap/'
        #     'sub-{subject_id}_ses-{session_id}_'
        #     'magnitude1_res-1x1x1_preproc.nii.gz',
    }

    inputfiles = pe.Node(nio.SelectFiles(templates, base_directory=data_dir),
                         name="input_files")

    featpreproc.connect([(inputnode, inputfiles, [
        ('subject_id', 'subject_id'),
        ('session_id', 'session_id'),
    ])])

    # ===================================================================
    #                   ____        _               _
    #                  / __ \      | |             | |
    #                 | |  | |_   _| |_ _ __  _   _| |_
    #                 | |  | | | | | __| '_ \| | | | __|
    #                 | |__| | |_| | |_| |_) | |_| | |_
    #                  \____/ \__,_|\__| .__/ \__,_|\__|
    #                                  | |
    #                                  |_|
    # ===================================================================

    # ------------------ Output Files
    # Datasink
    outputfiles = pe.Node(nio.DataSink(base_directory=ds_root,
                                       container='derivatives/featpreproc',
                                       parameterization=True),
                          name="output_files")

    # Use the following DataSink output substitutions
    # each tuple is only matched once per file
    outputfiles.inputs.substitutions = [
        ('/_mc_method_afni3dAllinSlices/', '/'),
        ('/_mc_method_afni3dAllinSlices/', '/'),  # needs to appear twice
        ('/oned_file/', '/'),
        ('/out_file/', '/'),
        ('/oned_matrix_save/', '/'),
        ('subject_id_', 'sub-'),
        ('session_id_', 'ses-'),
    ]
    # Put result into a BIDS-like format
    outputfiles.inputs.regexp_substitutions = [
        (r'_ses-([a-zA-Z0-9]+)_sub-([a-zA-Z0-9]+)', r'sub-\2/ses-\1'),
        (r'/_addmean[0-9]+/', r'/func/'),
        (r'/_funcbrains[0-9]+/', r'/func/'),
        (r'/_maskfunc[0-9]+/', r'/func/'),
        (r'/_mc[0-9]+/', r'/func/'),
        (r'/_meanfunc[0-9]+/', r'/func/'),
        (r'/_outliers[0-9]+/', r'/func/'),
        (r'_run_id_[0-9][0-9]', r''),
    ]
    outputnode = pe.Node(interface=util.IdentityInterface(fields=[
        'motion_parameters',
        'motion_corrected',
        'motion_plots',
        'motion_outlier_files',
        'mask',
        'smoothed_files',
        'highpassed_files',
        'mean',
        'func_unwarp',
        'ref_func',
        'ref_funcmask',
        'ref_t1',
        'ref_t1mask',
    ]),
                         name='outputspec')

    # ===================================================================
    #                  _____ _            _ _
    #                 |  __ (_)          | (_)
    #                 | |__) | _ __   ___| |_ _ __   ___
    #                 |  ___/ | '_ \ / _ \ | | '_ \ / _ \
    #                 | |   | | |_) |  __/ | | | | |  __/
    #                 |_|   |_| .__/ \___|_|_|_| |_|\___|
    #                         | |
    #                         |_|
    # ===================================================================

    #  ~|~ _ _  _  _ |` _  _ _ _    _ _  _  _|  _
    #   | | (_|| |_\~|~(_)| | | |  | | |(_|_\|<_\
    #
    # Transform manual skull-stripped masks to multiple images
    # --------------------------------------------------------
    # should just be used as input to motion correction,
    # after mc, all functionals should be aligned to reference
    transmanmask_mc = transform_manualmask.create_workflow()

    # - - - - - - Connections - - - - - - -
    featpreproc.connect([(inputfiles, transmanmask_mc, [
        ('subject_id', 'in.subject_id'),
        ('session_id', 'in.session_id'),
    ])])

    featpreproc.connect(inputfiles, 'ref_funcmask', transmanmask_mc,
                        'in.manualmask')
    featpreproc.connect(inputnode, 'funcs', transmanmask_mc, 'in.funcs')
    featpreproc.connect(inputfiles, 'ref_func', transmanmask_mc,
                        'in.manualmask_func_ref')

    # fieldmaps not being used
    if False:
        trans_fmapmask = transmanmask_mc.clone('trans_fmapmask')
        featpreproc.connect(inputfiles, 'ref_manual_fmapmask', trans_fmapmask,
                            'in.manualmask')
        featpreproc.connect(inputfiles, 'fmap_magnitude', trans_fmapmask,
                            'in.funcs')
        featpreproc.connect(inputfiles, 'ref_func', trans_fmapmask,
                            'in.manualmask_func_ref')

    #  |\/| _ _|_. _  _    _ _  _ _ _  __|_. _  _
    #  |  |(_) | |(_)| |  (_(_)| | (/_(_ | |(_)| |
    #
    # Perform motion correction, using some pipeline
    # --------------------------------------------------------
    # mc = motioncorrection_workflow.create_workflow_afni()

    # Register an image from the functionals to the reference image
    median_func = pe.MapNode(
        interface=fsl.maths.MedianImage(dimension="T"),
        name='median_func',
        iterfield=('in_file'),
    )
    pre_mc = motioncorrection_workflow.create_workflow_allin_slices(
        name='premotioncorrection')

    featpreproc.connect([
        (inputnode, median_func, [
            ('funcs', 'in_file'),
        ]),
        (median_func, pre_mc, [
            ('out_file', 'in.funcs'),
        ]),
        (
            inputfiles,
            pre_mc,
            [
                # median func image will be used a reference / base
                ('ref_func', 'in.ref_func'),
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            pre_mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'),  # use mask as weights
            ]),
        (pre_mc, outputnode, [
            ('mc.out_file', 'pre_motion_corrected'),
            ('mc.oned_file', 'pre_motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'pre_motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('pre_motion_corrected', 'pre_motion_corrected.out_file'),
                ('pre_motion_parameters.oned_file',
                 'pre_motion_corrected.oned_file'
                 ),  # warp parameters in ASCII (.1D)
                ('pre_motion_parameters.oned_matrix_save',
                 'pre_motion_corrected.oned_matrix_save'
                 ),  # transformation matrices for each sub-brick
            ]),
    ])

    mc = motioncorrection_workflow.create_workflow_allin_slices(
        name='motioncorrection',
        iterfield=('in_file', 'ref_file', 'in_weight_file'))
    # - - - - - - Connections - - - - - - -
    featpreproc.connect([
        (inputnode, mc, [
            ('funcs', 'in.funcs'),
        ]),
        (
            pre_mc,
            mc,
            [
                # the median image realigned to the reference functional will serve as reference
                #  this way motion correction is done to an image more similar to the functionals
                ('mc.out_file', 'in.ref_func'),
            ]),
        (
            inputfiles,
            mc,
            [
                # Check and make sure the ref func mask is close enough to the registered median
                # image.
                ('ref_funcmask', 'in.ref_func_weights'),
            ]),
        (
            transmanmask_mc,
            mc,
            [
                ('funcreg.out_file', 'in.funcs_masks'),  # use mask as weights
            ]),
        (mc, outputnode, [
            ('mc.out_file', 'motion_corrected'),
            ('mc.oned_file', 'motion_parameters.oned_file'),
            ('mc.oned_matrix_save', 'motion_parameters.oned_matrix_save'),
        ]),
        (
            outputnode,
            outputfiles,
            [
                ('motion_corrected', 'motion_corrected.out_file'),
                ('motion_parameters.oned_file', 'motion_corrected.oned_file'
                 ),  # warp parameters in ASCII (.1D)
                ('motion_parameters.oned_matrix_save',
                 'motion_corrected.oned_matrix_save'
                 ),  # transformation matrices for each sub-brick
            ]),
    ])

    #  |~. _ | _| _ _  _  _    _ _  _ _ _  __|_. _  _
    #  |~|(/_|(_|| | |(_||_)  (_(_)| | (/_(_ | |(_)| |
    #                    |
    # Unwarp EPI distortions
    # --------------------------------------------------------

    # Performing motion correction to a reference that is undistorted,
    # so b0_unwarp is currently not needed
    if False:
        b0_unwarp = undistort_workflow.create_workflow()

        featpreproc.connect([
            (
                inputfiles,
                b0_unwarp,
                [  # ('subject_id', 'in.subject_id'),
                    # ('session_id', 'in.session_id'),
                    ('fmap_phasediff', 'in.fmap_phasediff'),
                    ('fmap_magnitude', 'in.fmap_magnitude'),
                ]),
            (mc, b0_unwarp, [
                ('mc.out_file', 'in.funcs'),
            ]),
            (transmanmask_mc, b0_unwarp, [
                ('funcreg.out_file', 'in.funcmasks'),
            ]),
            (trans_fmapmask, b0_unwarp, [('funcreg.out_file', 'in.fmap_mask')
                                         ]),
            (b0_unwarp, outputfiles, [
                ('out.funcs', 'func_unwarp.funcs'),
                ('out.funcmasks', 'func_unwarp.funcmasks'),
            ]),
            (b0_unwarp, outputnode, [
                ('out.funcs', 'func_unwarp.funcs'),
                ('out.funcmasks', 'mask'),
            ]),
        ])

    # undistort the reference images
    if False:
        b0_unwarp_ref = b0_unwarp.clone('b0_unwarp_ref')
        featpreproc.connect([
            (
                inputfiles,
                b0_unwarp_ref,
                [  # ('subject_id', 'in.subject_id'),
                    # ('session_id', 'in.session_id'),
                    ('ref_fmap_phasediff', 'in.fmap_phasediff'),
                    ('ref_fmap_magnitude', 'in.fmap_magnitude'),
                    ('ref_manual_fmapmask', 'in.fmap_mask'),
                    ('ref_func', 'in.funcs'),
                    ('ref_funcmask', 'in.funcmasks'),
                ]),
            (b0_unwarp_ref, outputfiles, [
                ('out.funcs', 'func_unwarp_ref.func'),
                ('out.funcmasks', 'func_unwarp_ref.funcmask'),
            ]),
            (b0_unwarp_ref, outputnode, [
                ('out.funcs', 'ref_func'),
                ('out.funcmasks', 'ref_mask'),
            ]),
        ])
    else:
        featpreproc.connect([
            (inputfiles, outputfiles, [
                ('ref_func', 'reference/func'),
                ('ref_funcmask', 'reference/func_mask'),
            ]),
            (inputfiles, outputnode, [
                ('ref_func', 'ref_func'),
                ('ref_funcmask', 'ref_funcmask'),
            ]),
        ])

    # |~) _  _ . __|_ _  _  _|_ _   |~) _  |` _  _ _  _  _ _
    # |~\(/_(_||_\ | (/_|    | (_)  |~\(/_~|~(/_| (/_| |(_(/_
    #        _|
    # Register all functionals to common reference
    # --------------------------------------------------------
    if False:  # this is now done during motion correction
        # FLIRT cost: intermodal: corratio, intramodal: least squares and normcorr
        reg_to_ref = pe.MapNode(  # intra-modal
            # some runs need to be scaled along the anterior-posterior direction
            interface=fsl.FLIRT(dof=12, cost='normcorr'),
            name='reg_to_ref',
            iterfield=('in_file', 'in_weight'),
        )
        refEPI_to_refT1 = pe.Node(
            # some runs need to be scaled along the anterior-posterior direction
            interface=fsl.FLIRT(dof=12, cost='corratio'),
            name='refEPI_to_refT1',
        )
        # combine func -> ref_func and ref_func -> ref_T1
        reg_to_refT1 = pe.MapNode(
            interface=fsl.ConvertXFM(concat_xfm=True),
            name='reg_to_refT1',
            iterfield=('in_file'),
        )

        reg_funcs = pe.MapNode(
            interface=fsl.preprocess.ApplyXFM(),
            name='reg_funcs',
            iterfield=('in_file', 'in_matrix_file'),
        )
        reg_funcmasks = pe.MapNode(interface=fsl.preprocess.ApplyXFM(),
                                   name='reg_funcmasks',
                                   iterfield=('in_file', 'in_matrix_file'))

        def deref_list(x):
            assert len(x) == 1
            return x[0]

        featpreproc.connect([
            (
                b0_unwarp,
                reg_to_ref,  # --> reg_to_ref, (A)
                [
                    ('out.funcs', 'in_file'),
                    ('out.funcmasks', 'in_weight'),
                ]),
            (b0_unwarp_ref, reg_to_ref, [
                (('out.funcs', deref_list), 'reference'),
                (('out.funcmasks', deref_list), 'ref_weight'),
            ]),
            (
                b0_unwarp_ref,
                refEPI_to_refT1,  # --> refEPI_to_refT1 (B)
                [
                    (('out.funcs', deref_list), 'in_file'),
                    (('out.funcmasks', deref_list), 'in_weight'),
                ]),
            (inputfiles, refEPI_to_refT1, [
                ('ref_t1', 'reference'),
                ('ref_t1mask', 'ref_weight'),
            ]),
            (
                reg_to_ref,
                reg_to_refT1,  # --> reg_to_refT1 (A*B)
                [
                    ('out_matrix_file', 'in_file'),
                ]),
            (refEPI_to_refT1, reg_to_refT1, [
                ('out_matrix_file', 'in_file2'),
            ]),
            (
                reg_to_refT1,
                reg_funcs,  # --> reg_funcs
                [
                    # ('out_matrix_file', 'in_matrix_file'),
                    ('out_file', 'in_matrix_file'),
                ]),
            (b0_unwarp, reg_funcs, [
                ('out.funcs', 'in_file'),
            ]),
            (b0_unwarp_ref, reg_funcs, [
                (('out.funcs', deref_list), 'reference'),
            ]),
            (
                reg_to_refT1,
                reg_funcmasks,  # --> reg_funcmasks
                [
                    # ('out_matrix_file', 'in_matrix_file'),
                    ('out_file', 'in_matrix_file'),
                ]),
            (b0_unwarp, reg_funcmasks, [
                ('out.funcmasks', 'in_file'),
            ]),
            (b0_unwarp_ref, reg_funcmasks, [
                (('out.funcs', deref_list), 'reference'),
            ]),
            (reg_funcs, outputfiles, [
                ('out_file', 'common_ref.func'),
            ]),
            (reg_funcmasks, outputfiles, [
                ('out_file', 'common_ref.funcmask'),
            ]),
        ])

    #  |\/| _ _|_. _  _    _   _|_|. _  _ _
    #  |  |(_) | |(_)| |  (_)|_|| ||(/_| _\
    #
    # --------------------------------------------------------

    # Apply brain masks to functionals
    # --------------------------------------------------------

    # Dilate mask
    """
    Dilate the mask
    """
    if False:
        dilatemask = pe.MapNode(interface=fsl.ImageMaths(suffix='_dil',
                                                         op_string='-dilF'),
                                iterfield=['in_file'],
                                name='dilatemask')
        featpreproc.connect(reg_funcmasks, 'out_file', dilatemask, 'in_file')
    else:
        dilatemask = pe.Node(interface=fsl.ImageMaths(suffix='_dil',
                                                      op_string='-dilF'),
                             name='dilatemask')
        featpreproc.connect(inputfiles, 'ref_funcmask', dilatemask, 'in_file')

    featpreproc.connect(dilatemask, 'out_file', outputfiles, 'dilate_mask')

    funcbrains = pe.MapNode(fsl.BinaryMaths(operation='mul'),
                            iterfield=('in_file', 'operand_file'),
                            name='funcbrains')

    featpreproc.connect([
        (mc, funcbrains, [
            ('mc.out_file', 'in_file'),
        ]),
        (dilatemask, funcbrains, [
            ('out_file', 'operand_file'),
        ]),
        (funcbrains, outputfiles, [
            ('out_file', 'funcbrains'),
        ]),
    ])
    # Detect motion outliers
    # --------------------------------------------------------

    import nipype.algorithms.rapidart as ra
    outliers = pe.MapNode(
        ra.ArtifactDetect(
            mask_type='file',
            # trying to "disable" `norm_threshold`:
            use_norm=True,
            norm_threshold=10.0,  # combines translations in mm and rotations
            # use_norm=Undefined,
            # translation_threshold=1.0,  # translation in mm
            # rotation_threshold=0.02,  # rotation in radians
            zintensity_threshold=3.0,  # z-score
            parameter_source='AFNI',
            save_plot=True),
        iterfield=('realigned_files', 'realignment_parameters', 'mask_file'),
        name='outliers')

    featpreproc.connect([
        (
            mc,
            outliers,
            [  # ('mc.par_file', 'realignment_parameters'),
                ('mc.oned_file', 'realignment_parameters'),
            ]),
        (funcbrains, outliers, [
            ('out_file', 'realigned_files'),
        ]),
        (dilatemask, outliers, [
            ('out_file', 'mask_file'),
        ]),
        (
            outliers,
            outputfiles,
            [
                ('outlier_files', 'motion_outliers.@outlier_files'),
                ('plot_files', 'motion_outliers.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ]),
        (mc, outputnode, [
            ('mc.oned_file', 'motion_parameters'),
        ]),
        (
            outliers,
            outputnode,
            [
                ('outlier_files', 'motion_outlier_files'),
                ('plot_files', 'motion_plots.@plot_files'),
                ('displacement_files', 'motion_outliers.@displacement_files'),
                ('intensity_files', 'motion_outliers.@intensity_files'),
                ('mask_files', 'motion_outliers.@mask_files'),
                ('statistic_files', 'motion_outliers.@statistic_files'),
                # ('norm_files', 'outliers.@norm_files'),
            ])
    ])
    """
    Determine the 2nd and 98th percentile intensities of each functional run
    """
    getthresh = pe.MapNode(interface=fsl.ImageStats(op_string='-p 2 -p 98'),
                           iterfield=['in_file'],
                           name='getthreshold')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', getthresh, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', getthresh, 'in_file')
    """
    Threshold the first run of functional data at 10% of the 98th percentile
    """

    threshold = pe.MapNode(interface=fsl.ImageMaths(out_data_type='char',
                                                    suffix='_thresh'),
                           iterfield=['in_file', 'op_string'],
                           name='threshold')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', threshold, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', threshold, 'in_file')
    """
    Define a function to get 10% of the intensity
    """
    def getthreshop(thresh):
        return ['-thr %.10f -Tmin -bin' % (0.1 * val[1]) for val in thresh]

    featpreproc.connect(getthresh, ('out_stat', getthreshop), threshold,
                        'op_string')
    """
    Determine the median value of the functional runs using the mask
    """
    medianval = pe.MapNode(interface=fsl.ImageStats(op_string='-k %s -p 50'),
                           iterfield=['in_file', 'mask_file'],
                           name='medianval')
    if False:
        featpreproc.connect(b0_unwarp, 'out.funcs', medianval, 'in_file')
    else:
        featpreproc.connect(mc, 'mc.out_file', medianval, 'in_file')

    featpreproc.connect(threshold, 'out_file', medianval, 'mask_file')

    # (~ _  _ _|_. _ |  (~ _ _  _  _ _|_|_ . _  _
    # _)|_)(_| | |(_||  _)| | |(_)(_) | | ||| |(_|
    #   |                                       _|
    # Spatial smoothing (SUSAN)
    # --------------------------------------------------------

    # create_susan_smooth takes care of calculating the mean and median
    #   functional, applying mask to functional, and running the smoothing
    smooth = create_susan_smooth(separate_masks=False)
    featpreproc.connect(inputnode, 'fwhm', smooth, 'inputnode.fwhm')

    # featpreproc.connect(b0_unwarp, 'out.funcs', smooth, 'inputnode.in_files')
    if False:
        featpreproc.connect(reg_funcs, 'out_file', smooth,
                            'inputnode.in_files')
    else:
        featpreproc.connect(mc, 'mc.out_file', smooth, 'inputnode.in_files')

    featpreproc.connect(dilatemask, 'out_file', smooth, 'inputnode.mask_file')

    # -------------------------------------------------------
    # The below is from workflows/fmri/fsl/preprocess.py
    """
    Mask the smoothed data with the dilated mask
    """

    maskfunc3 = pe.MapNode(interface=fsl.ImageMaths(suffix='_mask',
                                                    op_string='-mas'),
                           iterfield=['in_file', 'in_file2'],
                           name='maskfunc3')
    featpreproc.connect(smooth, 'outputnode.smoothed_files', maskfunc3,
                        'in_file')

    featpreproc.connect(dilatemask, 'out_file', maskfunc3, 'in_file2')

    concatnode = pe.Node(interface=util.Merge(2), name='concat')

    tolist = lambda x: [x]

    def chooseindex(fwhm):
        if fwhm < 1:
            return [0]
        else:
            return [1]

    # maskfunc2 is the functional data before SUSAN
    if False:
        featpreproc.connect(b0_unwarp, ('out.funcs', tolist), concatnode,
                            'in1')
    else:
        featpreproc.connect(mc, ('mc.out_file', tolist), concatnode, 'in1')
    # maskfunc3 is the functional data after SUSAN
    featpreproc.connect(maskfunc3, ('out_file', tolist), concatnode, 'in2')
    """
    The following nodes select smooth or unsmoothed data depending on the
    fwhm. This is because SUSAN defaults to smoothing the data with about the
    voxel size of the input data if the fwhm parameter is less than 1/3 of the
    voxel size.
    """
    selectnode = pe.Node(interface=util.Select(), name='select')

    featpreproc.connect(concatnode, 'out', selectnode, 'inlist')

    featpreproc.connect(inputnode, ('fwhm', chooseindex), selectnode, 'index')
    featpreproc.connect(selectnode, 'out', outputfiles, 'smoothed_files')
    """
    Scale the median value of the run is set to 10000.
    """

    meanscale = pe.MapNode(interface=fsl.ImageMaths(suffix='_gms'),
                           iterfield=['in_file', 'op_string'],
                           name='meanscale')
    featpreproc.connect(selectnode, 'out', meanscale, 'in_file')
    """
    Define a function to get the scaling factor for intensity normalization
    """

    featpreproc.connect(medianval, ('out_stat', getmeanscale), meanscale,
                        'op_string')

    # |_|. _ |_  _  _  _ _
    # | ||(_|| ||_)(_|_\_\
    #      _|   |
    # Temporal filtering
    # --------------------------------------------------------

    highpass = pe.MapNode(interface=fsl.ImageMaths(suffix='_tempfilt'),
                          iterfield=['in_file'],
                          name='highpass')
    highpass_operand = lambda x: '-bptf %.10f -1' % x
    featpreproc.connect(inputnode, ('highpass', highpass_operand), highpass,
                        'op_string')
    featpreproc.connect(meanscale, 'out_file', highpass, 'in_file')

    version = 0
    if fsl.Info.version() and \
            LooseVersion(fsl.Info.version()) > LooseVersion('5.0.6'):
        version = 507

    if version < 507:
        featpreproc.connect(highpass, 'out_file', outputnode,
                            'highpassed_files')
    else:
        """
        Add back the mean removed by the highpass filter operation as
            of FSL 5.0.7
        """
        meanfunc4 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                        suffix='_mean'),
                               iterfield=['in_file'],
                               name='meanfunc4')

        featpreproc.connect(meanscale, 'out_file', meanfunc4, 'in_file')
        addmean = pe.MapNode(interface=fsl.BinaryMaths(operation='add'),
                             iterfield=['in_file', 'operand_file'],
                             name='addmean')
        featpreproc.connect(highpass, 'out_file', addmean, 'in_file')
        featpreproc.connect(meanfunc4, 'out_file', addmean, 'operand_file')
        featpreproc.connect(addmean, 'out_file', outputnode,
                            'highpassed_files')
    """
    Generate a mean functional image from the first run
    """
    meanfunc3 = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean',
                                                    suffix='_mean'),
                           iterfield=['in_file'],
                           name='meanfunc3')

    featpreproc.connect(meanscale, 'out_file', meanfunc3, 'in_file')
    featpreproc.connect(meanfunc3, 'out_file', outputfiles, 'mean')

    featpreproc.connect(meanfunc3, 'out_file', outputnode, 'mean_highpassed')
    featpreproc.connect(outputnode, 'highpassed_files', outputfiles,
                        'highpassed_files')

    return (featpreproc)