def create_nuisance_evs_workflow(freesurfer_dir, fwhm, name="nuisance_evs"):
    
    #####
    # Setup workflow
    #####
    
    wf = pe.Workflow(name=name)
    
    
    #####
    # Setup input node
    #####
    
    input_fields = [
        # segment
        "subject_id",       # required
        "freesurfer_dir", 
        "orientation", 
        # mask creation
        "brain_mask",       # required
        "reg_dir",          # required
        "csf_prior", 
        "csf_erode", 
        "csf_threshold", 
        "wm_prior", 
        "wm_erode", 
        "wm_threshold",
        # ts extraction 
        "func",             # required
    ]
    inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), 
                            name="inputspec")
    
    # defaults
    inputnode.inputs.freesurfer_dir = freesurfer_dir
    inputnode.inputs.orientation = 'RPI'
    inputnode.inputs.csf_prior = fsl_prior_path("csf")
    inputnode.inputs.csf_erode = 0
    inputnode.inputs.csf_threshold = 0.75
    inputnode.inputs.wm_prior = fsl_prior_path("white")
    inputnode.inputs.wm_erode = 2
    inputnode.inputs.wm_threshold = 0.75
        
    
    #####
    # Setup output node
    #####
    
    # Outputs
    output_fields_highres = [
        # segmentation
        "csf",
        "wm",
        "gm",
        "csf_pic",
        "wm_pic",
        "gm_pic"
    ]
    outputnode_highres = pe.Node(util.IdentityInterface(fields=output_fields_highres),
                                                        name="outputspec_highres")
    
    output_fields_func = [
        # masks
        "mask_global", 
        "mask_csf",
        "mask_wm",
        "mask_global_pic", 
        "mask_csf_pic", 
        "mask_wm_pic", 
        # ts
        "ts_global",
        "ts_csf",
        "ts_wm",
        "tsplot_global_pic", 
        "tsplot_csf_pic", 
        "tsplot_wm_pic", 
        "tsplot_all_pic",
    ]
    outputnode_func = pe.Node(util.IdentityInterface(fields=output_fields_func),
                                                     name="outputspec_func")
    
    # renaming
    renamer_highres = SimpleOutputConnector(wf, outputnode_highres)
    renamer_func = SimpleOutputConnector(wf, outputnode_func)
    
    
    #####
    # COMMANDS
    #####
    
    # Segment Brain
    segment = create_tissue_masks(freesurfer_dir, name="01_segment")
    wf.connect([
        (inputnode, segment, [('subject_id', 'inputspec.subject_id'),
                              ('freesurfer_dir', 'inputspec.freesurfer_dir'),
                              ('orientation', 'inputspec.orientation')]),
        (segment, outputnode_highres, [('outputspec.csf', 'csf'),
                                       ('outputspec.wm', 'wm'),
                                       ('outputspec.gm', 'gm'), 
                                       ('outputspec.csf_pic', 'csf_pic'), 
                                       ('outputspec.wm_pic', 'wm_pic'),
                                       ('outputspec.gm_pic', 'gm_pic')])
    ])
    
    # Create CSF mask
    csfmask = create_nuisance_mask_workflow(name="02_mask_csf", fwhm=fwhm, mask_fprefix='mask_csf', 
                                                freesurfer_dir=freesurfer_dir)
    wf.connect([
        (segment, csfmask, [('outputspec.csf', 'inputspec.mask_file')]), 
        (inputnode, csfmask, [('brain_mask', 'inputspec.brain_mask_file'),
                              ('csf_prior', 'inputspec.prior_file'),
                              ('reg_dir', 'inputspec.reg_dir'),
                              ('freesurfer_dir', 'inputspec.freesurfer_dir'),
                              ('csf_erode', 'inputspec.erode'),
                              ('csf_threshold', 'inputspec.threshold')]), 
        (csfmask, outputnode_func, [('outputspec.mask', 'mask_csf'),
                                    ('outputspec.mask_pic', 'mask_csf_pic')])
    ])
    
    # Create WM mask
    wmmask = create_nuisance_mask_workflow(name="02_mask_wm", fwhm=fwhm, mask_fprefix='mask_wm', 
                                            freesurfer_dir=freesurfer_dir)
    wf.connect([
        (segment, wmmask, [('outputspec.wm', 'inputspec.mask_file')]), 
        (inputnode, wmmask, [('brain_mask', 'inputspec.brain_mask_file'),
                              ('wm_prior', 'inputspec.prior_file'),
                              ('reg_dir', 'inputspec.reg_dir'),
                              ('freesurfer_dir', 'inputspec.freesurfer_dir'),
                              ('wm_erode', 'inputspec.erode'),
                              ('wm_threshold', 'inputspec.threshold')]),
        (wmmask, outputnode_func, [('outputspec.mask', 'mask_wm'),
                                   ('outputspec.mask_pic', 'mask_wm_pic')])
    ])
    
    # Global mask (copy and pic)
    slicer_global = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), 
                         name='02_mask_global')
    wf.connect(inputnode, ('reg_dir', regpath, 'func.*'), slicer_global, 'in_file')
    wf.connect(inputnode, ('brain_mask', get_overlay_args), slicer_global, 'overlay1')
    renamer_func.connect(slicer_global, 'out_file', 'mask_global_pic')
    renamer_func.connect(inputnode, 'brain_mask', 'mask_global')
    
    
    # Extract TS for global
    meants_global = pe.Node(fsl.ImageMeants(), 
                            name="03_meants_global")
    wf.connect([
        (inputnode, meants_global, [('func', 'in_file'),
                                     ('brain_mask', 'mask')])
    ])
    renamer_func.connect(meants_global, 'out_file', 'ts_global')    
    
    # Extract TS for csf
    meants_csf = pe.Node(fsl.ImageMeants(), 
                            name="03_meants_csf")
    wf.connect([
        (inputnode, meants_csf, [('func', 'in_file')]),
        (csfmask, meants_csf, [('outputspec.mask', 'mask')]),
    ])
    renamer_func.connect(meants_csf, 'out_file', 'ts_csf')
    
    # Extract TS for wm
    meants_wm = pe.Node(fsl.ImageMeants(), 
                            name="03_meants_wm")
    wf.connect([
        (inputnode, meants_wm, [('func', 'in_file')]),
        (wmmask, meants_wm, [('outputspec.mask', 'mask')]),
    ])
    renamer_func.connect(meants_wm, 'out_file', 'ts_wm')
    
    # Create plot
    ## concat
    concatnode = pe.Node(interface=util.Merge(3),
                         name='04_concat')
    wf.connect(meants_global, ('out_file', tolist), concatnode, 'in1')
    wf.connect(meants_csf, ('out_file', tolist), concatnode, 'in2')
    wf.connect(meants_wm, ('out_file', tolist), concatnode, 'in3')
    ## plot
    tsplot_all = pe.Node(interface=fsl.PlotTimeSeries(title='Nuisance Time-Series', 
                                                      labels=['global', 'csf', 'wm']), 
                     name="04_tsplot_all")
    wf.connect(concatnode, 'out', tsplot_all, 'in_file')
    renamer_func.connect(tsplot_all, 'out_file', 'tsplot_all_pic')
    
    # Independent plots!
    ## global
    tsplot_global = pe.Node(interface=fsl.PlotTimeSeries(title='Global Time-Series'), 
                     name="04_tsplot_global")
    wf.connect(meants_global, 'out_file', tsplot_global, 'in_file')
    renamer_func.connect(tsplot_global, 'out_file', 'tsplot_global_pic')
    ## csf
    tsplot_csf = pe.Node(interface=fsl.PlotTimeSeries(title='CSF Time-Series'), 
                     name="04_tsplot_csf")
    wf.connect(meants_csf, 'out_file', tsplot_csf, 'in_file')
    renamer_func.connect(tsplot_csf, 'out_file', 'tsplot_csf_pic')    
    ## wm
    tsplot_wm = pe.Node(interface=fsl.PlotTimeSeries(title='White-Matter Time-Series'), 
                     name="04_tsplot_wm")
    wf.connect(meants_wm, 'out_file', tsplot_wm, 'in_file')
    renamer_func.connect(tsplot_wm, 'out_file', 'tsplot_wm_pic')    
    
    return wf
def create_tissue_masks(freesurfer_dir, name="segmentation"):
    """Generates masks of each tissue type (GM, WM, and CSF) using freesurfer.
    PNG images of each tissue type is also created for QC.
    """
    
    #####
    # Setup workflow
    #####
    
    ctissues = pe.Workflow(name=name)
    
    
    #####
    # Setup input node
    #####
    
    input_fields = [
        "subject_id",
        "freesurfer_dir",   # $SUBJECTS_DIR
        "orientation"
    ]
    inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), 
                            name="inputspec")
    
    # defaults
    inputnode.inputs.orientation = "RPI"    # fsl's standard brain
    
    
    #####
    # Setup output node
    #####
    
    # Outputs
    output_fields = [
        "aseg",
        "csf",
        "wm",
        "gm",
        "csf_pic",
        "wm_pic",
        "gm_pic"
    ]
    outputnode = pe.Node(util.IdentityInterface(fields=output_fields),
                        name="outputspec")
    
    # renaming
    renamer = SimpleOutputConnector(ctissues, outputnode)
    
    
    ######
    # Commands
    ######
    
    # First call a function that may or may not run autorecon1
    segment = pe.Node(run_freesurfer, name="segment")
    segment.inputs.directive = 'autorecon2'
    segment.inputs.subjects_dir = freesurfer_dir
    ctissues.connect([
        (inputnode, segment, [('subject_id', 'subject_id'),
                              ('freesurfer_dir', 'subjects_dir')])
    ])
    
    # Now get inputs
    getfree = pe.Node(nio.FreeSurferSource(subjects_dir=freesurfer_dir),
                      name="getfree")
    ctissues.connect([
        (inputnode, getfree, [('freesurfer_dir', 'subjects_dir')]),
        (segment, getfree, [('subject_id', 'subject_id')])
    ])
    
    # Save head => nii.gz
    convert_aseg = pe.Node(fs.MRIConvert(out_type="niigz", subjects_dir=freesurfer_dir), 
                           name="convert_orig")
    ctissues.connect(getfree, 'aseg', convert_aseg, 'in_file')
    ctissues.connect(inputnode, 'orientation', convert_aseg, 'out_orientation')
    ## reorient for sure
    reorient_aseg = pe.Node(interface=afni.Threedresample(), name='reorient_aseg')
    ctissues.connect(convert_aseg, 'out_file', reorient_aseg, 'in_file')
    ctissues.connect(inputnode, 'orientation', reorient_aseg, 'orientation')
    renamer(reorient_aseg, 'out_file', 'aseg')
    
    # Save brain => nii.gz
    convert_brain = pe.Node(fs.MRIConvert(out_type="niigz", subjects_dir=freesurfer_dir), 
                            name="convert_brain")
    ctissues.connect(getfree, 'brainmask', convert_brain, 'in_file')
    ctissues.connect(inputnode, 'orientation', convert_brain, 'out_orientation')
    ## reorient for sure
    reorient_brain = pe.Node(interface=afni.Threedresample(), name='reorient_brain')
    ctissues.connect(convert_brain, 'out_file', reorient_brain, 'in_file')
    ctissues.connect(inputnode, 'orientation', reorient_brain, 'orientation')
    
    # Extract and erode a mask of the deep cerebral white matter
    extractwm = pe.Node(fs.Binarize(match=[2, 41], subjects_dir=freesurfer_dir, out_type="nii.gz"), 
                        name="extractwm")
    ctissues.connect([
        (inputnode, extractwm, [('freesurfer_dir', 'subjects_dir')]),
        (reorient_aseg, extractwm, [('out_file', 'in_file')])
    ])
    renamer.connect(extractwm, 'binary_file', 'wm')
    
    ## pic
    slicer_wm = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), 
                        name='slicer_wm')
    ctissues.connect(reorient_brain, 'out_file', slicer_wm, 'in_file')
    ctissues.connect(extractwm, ('binary_file', get_overlay_args), slicer_wm, 'overlay1')
    renamer.connect(slicer_wm, 'out_file', 'wm_pic')
        
    # Extract and erode a mask of the ventricles and CSF
    extractcsf = pe.Node(fs.Binarize(match=[4, 5, 14, 15, 24, 31, 43, 44, 63], 
                                        subjects_dir=freesurfer_dir, out_type="nii.gz"),
                         name="extractcsf")
    ctissues.connect([
        (inputnode, extractcsf, [('freesurfer_dir', 'subjects_dir')]),
        (reorient_aseg, extractcsf, [('out_file', 'in_file')])
    ])
    renamer.connect(extractcsf, 'binary_file', 'csf')
    
    ## pic
    slicer_csf = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), 
                         name='slicer_csf')
    ctissues.connect(reorient_brain, 'out_file', slicer_csf, 'in_file')
    ctissues.connect(extractcsf, ('binary_file', get_overlay_args), slicer_csf, 'overlay1')
    renamer.connect(slicer_csf, 'out_file', 'csf_pic')
    
    # Extract a mask of the grey matter and subcortical areas and brainstem
    extractgm = pe.Node(
        fs.Binarize(match=[3,8,10,11,12,13,16,17,18,26,28,42,47,49,50,51,52,54,58,60], 
                    subjects_dir=freesurfer_dir, out_type="nii.gz"), 
        name="extractgm"
    )
    ctissues.connect([
        (inputnode, extractgm, [('freesurfer_dir', 'subjects_dir')]),
        (reorient_aseg, extractgm, [('out_file', 'in_file')])
    ])
    renamer.connect(extractgm, 'binary_file', 'gm')
    
    ## pic
    slicer_gm = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), 
                         name='slicer_gm')
    ctissues.connect(reorient_brain, 'out_file', slicer_gm, 'in_file')
    ctissues.connect(extractgm, ('binary_file', get_overlay_args), slicer_gm, 'overlay1')
    renamer.connect(slicer_gm, 'out_file', 'gm_pic')
    
    return ctissues
def create_nuisance_mask_workflow(fwhm, mask_fprefix, freesurfer_dir, name="nuisance_mask"):
    """Transforms a csf/wm/gm mask from anatomical to functional space and then some.
    """
    
    #####
    # Setup workflow
    #####
    
    nuisance = pe.Workflow(name=name)
    
    
    #####
    # Setup input node
    #####
    
    input_fields = [
        "mask_file",
        "prior_file",
        "reg_dir",
        "brain_mask_file",
        "erode", 
        "threshold",
        "freesurfer_dir"
    ]
    inputnode = pe.Node(interface=util.IdentityInterface(fields=input_fields), 
                            name="inputspec")
    
    inputnode.inputs.threshold = 0.75
    
    
    #####
    # Setup output node
    #####
    
    # Outputs
    output_fields = [
        "mask",
        "mask_pic"
    ]
    outputnode = pe.Node(util.IdentityInterface(fields=output_fields),
                        name="outputspec")
    
    # renaming
    renamer = SimpleOutputConnector(nuisance, outputnode)
    
    
    #####
    # Commands
    #####
    
    # 1. erode
    erode = pe.Node(fs.Binarize(match=[1], subjects_dir=freesurfer_dir), name="01_erode")
    nuisance.connect([
        (inputnode, erode, [('mask_file', 'in_file'),
                            ('erode', 'erode'),
                            ('freesurfer_dir', 'subjects_dir')])
    ])
    
    # 2. anat space => func space
    mask2func = pe.Node(fsl.ApplyXfm(apply_xfm=True, interp="trilinear"), 
                        name="02_mask2func")
    nuisance.connect([
        (erode, mask2func, [('binary_file', 'in_file')]),
        (inputnode, mask2func, [(('reg_dir', regpath, 'func.*'), 'reference'),
                                (('reg_dir', regpath, 'highres2func.mat'), 'in_matrix_file')])
    ])
    
    # 3. smooth
    if fwhm > 0:
        smooth = pe.Node(fsl.IsotropicSmooth(fwhm=fwhm), 
                         name="03_smooth")
        nuisance.connect([
            (mask2func, smooth, [('out_file', 'in_file')])
        ])
        nextnode = smooth
    else:
        nextnode = anat2func
    
    # 4. prior: std space => func space
    prior2func = pe.Node(fsl.ApplyXfm(apply_xfm=True, interp="nearestneighbour"), 
                     name="04_prior2func")
    nuisance.connect([
        (inputnode, prior2func, [('prior_file', 'in_file'), 
                                 (('reg_dir', regpath, 'func.*'), 'reference'),
                                 (('reg_dir', regpath, 'standard2func.mat'), 'in_matrix_file')])
    ])
    
    # 5. mask by prior
    prior_masked = pe.Node(fsl.ApplyMask(),
                           name="05_prior_masked")
    nuisance.connect([
        (nextnode, prior_masked, [('out_file', 'in_file')]),
        (prior2func, prior_masked, [('out_file', 'mask_file')])
    ])
    
    # 6. threshold
    threshold = pe.Node(fsl.Threshold(direction="below"),
                        name="06_threshold")
    nuisance.connect(inputnode, 'threshold', threshold, 'thresh')
    nuisance.connect(prior_masked, 'out_file', threshold, 'in_file')
    
    # 7. binarize
    binarize = pe.Node(fsl.UnaryMaths(operation="bin"),
                        name="07_binarize")
    nuisance.connect(threshold, 'out_file', binarize, 'in_file')
    
    # 8. mask by brain
    brain_masked = pe.Node(fsl.ApplyMask(),
                           name="08_brain_masked")
    nuisance.connect([
        (binarize, brain_masked, [('out_file', 'in_file')]),
        (inputnode, brain_masked, [('brain_mask_file', 'mask_file')])
    ])
    renamer.connect(brain_masked, 'out_file', 'mask', format_string=mask_fprefix)
    
    # 9. picture of mask over func
    slicer_mask = pe.Node(interface=misc.Slicer(width=5, height=4, slice_name="axial"), 
                         name='09_slicer_mask')
    nuisance.connect(inputnode, ('reg_dir', regpath, 'func.*'), slicer_mask, 'in_file')
    nuisance.connect(brain_masked, ('out_file', get_overlay_args), slicer_mask, 'overlay1')
    renamer.connect(slicer_mask, 'out_file', 'mask_pic', format_string=mask_fprefix)
    
    return nuisance