def extract_timeseries(SinkTag="connectivity", wf_name="extract_timeseries", modularise=True): ######################################################################## # Extract timeseries ######################################################################## import nipype.interfaces.nilearn as learn import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.io as io from nipype.interfaces.utility import Function import PUMI.utils.globals as globals import PUMI.utils.QC as qc import os SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Identitiy mapping for input variables inputspec = pe.Node( utility.IdentityInterface(fields=[ 'std_func', 'atlas_file', # nii labelmap (or 4D probmaps) 'labels', # list of short names to regions 'modules' # list of modules of regions ]), name='inputspec') # re-label atlas, so that regions corresponding to the same modules follow each other if modularise: relabel_atls = pe.Node(interface=Function( input_names=['atlas_file', 'modules', 'labels'], output_names=[ 'relabelled_atlas_file', 'reordered_modules', 'reordered_labels', 'newlabels_file' ], function=relabel_atlas), name='relabel_atlas') # Save outputs which are important ds_nii = pe.Node(interface=io.DataSink(), name='ds_relabeled_atlas') ds_nii.inputs.base_directory = SinkDir ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # Save outputs which are important ds_newlabels = pe.Node(interface=io.DataSink(), name='ds_newlabels') ds_newlabels.inputs.base_directory = SinkDir ds_newlabels.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".tsv")] extract_timesereies = pe.MapNode( interface=learn.SignalExtraction(detrend=False), iterfield=['in_file'], name='extract_timeseries') # Save outputs which are important ds_txt = pe.Node(interface=io.DataSink(), name='ds_txt') ds_txt.inputs.base_directory = SinkDir ds_txt.inputs.regexp_substitutions = [("(\/)[^\/]*$", wf_name + ".tsv")] #QC timeseries_qc = qc.regTimeseriesQC("regional_timeseries", tag=wf_name) outputspec = pe.Node(utility.IdentityInterface(fields=[ 'timeseries_file', 'relabelled_atlas_file', 'reordered_modules', 'reordered_labels' ]), name='outputspec') # Create workflow analysisflow = pe.Workflow(wf_name) analysisflow.connect(inputspec, 'std_func', extract_timesereies, 'in_file') if modularise: analysisflow.connect(inputspec, 'atlas_file', relabel_atls, 'atlas_file') analysisflow.connect(inputspec, 'modules', relabel_atls, 'modules') analysisflow.connect(inputspec, 'labels', relabel_atls, 'labels') analysisflow.connect(relabel_atls, 'relabelled_atlas_file', extract_timesereies, 'label_files') analysisflow.connect(relabel_atls, 'reordered_labels', extract_timesereies, 'class_labels') analysisflow.connect(relabel_atls, 'reordered_modules', timeseries_qc, 'inputspec.modules') analysisflow.connect(relabel_atls, 'relabelled_atlas_file', timeseries_qc, 'inputspec.atlas') analysisflow.connect(relabel_atls, 'relabelled_atlas_file', ds_nii, 'atlas_relabeled') analysisflow.connect(relabel_atls, 'newlabels_file', ds_newlabels, 'atlas_relabeled') analysisflow.connect(relabel_atls, 'relabelled_atlas_file', outputspec, 'relabelled_atlas_file') analysisflow.connect(relabel_atls, 'reordered_labels', outputspec, 'reordered_labels') analysisflow.connect(relabel_atls, 'reordered_modules', outputspec, 'reordered_modules') else: analysisflow.connect(inputspec, 'atlas_file', extract_timesereies, 'label_files') analysisflow.connect(inputspec, 'labels', extract_timesereies, 'class_labels') analysisflow.connect(inputspec, 'modules', timeseries_qc, 'inputspec.modules') analysisflow.connect(inputspec, 'atlas_file', timeseries_qc, 'inputspec.atlas') analysisflow.connect(inputspec, 'atlas_file', outputspec, 'relabelled_atlas_file') analysisflow.connect(inputspec, 'labels', outputspec, 'reordered_labels') analysisflow.connect(inputspec, 'modules', outputspec, 'reordered_modules') analysisflow.connect(extract_timesereies, 'out_file', ds_txt, 'regional_timeseries') analysisflow.connect(extract_timesereies, 'out_file', timeseries_qc, 'inputspec.timeseries') analysisflow.connect(extract_timesereies, 'out_file', outputspec, 'timeseries_file') return analysisflow
def anat2mni_ants_workflow_harcoded(SinkTag="anat_preproc", wf_name="anat2mni_ants"): """ Register skull and brain extracted image to MNI space and return the transformation martices. Using ANTS, doing it with a hardcoded function, a'la C-PAC. This uses brain masks and full head images, as well. Workflow inputs: :param skull: The reoriented anatomical file. :param brain: The brain extracted anat. :param ref_skull: MNI152 skull file. :param ref_brain: MNI152 brain file. :param SinkDir: :param SinkTag: The output directiry in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: anat2mni_workflow - workflow anat="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres.nii.gz", brain="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres_brain.nii.gz", Tamas Spisak [email protected] 2018 """ from nipype.interfaces.utility import Function SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Define inputs of workflow inputspec = pe.Node(utility.IdentityInterface( fields=['brain', 'skull', 'reference_brain', 'reference_skull']), name='inputspec') inputspec.inputs.reference_brain = globals._FSLDIR_ + globals._brainref #TODO_ready: 1 or 2mm??? inputspec.inputs.reference_skull = globals._FSLDIR_ + globals._headref # Multi-stage registration node with ANTS reg = pe.MapNode(interface=Function(input_names=[ 'anatomical_brain', 'reference_brain', 'anatomical_skull', 'reference_skull' ], output_names=[ 'transform_composite', 'transform_inverse_composite', 'warped_image' ], function=hardcoded_reg_fast), iterfield=['anatomical_brain', 'anatomical_skull'], name="ANTS_hardcoded", mem_gb=4.1) # Calculate linear transformation with FSL. This matrix has to be used in segmentation with fast if priors are set. (the default). # Linear registration node linear_reg = pe.MapNode(interface=fsl.FLIRT(), iterfield=['in_file'], name='linear_reg_0') linear_reg.inputs.cost = 'corratio' # Calculate the invers of the linear transformation inv_flirt_xfm = pe.MapNode(interface=fsl.utils.ConvertXFM(), iterfield=['in_file'], name='inv_linear_reg0_xfm') inv_flirt_xfm.inputs.invert_xfm = True # # or hardcoded_reg_cpac # Create png images for quality check myqc = qc.vol2png("anat2mni", "ANTS", overlayiterated=False) myqc.inputs.inputspec.overlay_image = globals._FSLDIR_ + globals._brainref #TODO_ready: 1 or 2mm??? myqc.inputs.slicer.image_width = 500 # 5000 # for the 1mm template myqc.inputs.slicer.threshold_edges = 0.1 # 0.1 # for the 1mm template # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds_nii') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # Define outputs of the workflow outputspec = pe.Node(utility.IdentityInterface(fields=[ 'output_brain', 'linear_xfm', 'invlinear_xfm', 'nonlinear_xfm', 'invnonlinear_xfm', 'std_template' ]), name='outputspec') outputspec.inputs.std_template = inputspec.inputs.reference_brain # Create workflow nad connect nodes analysisflow = pe.Workflow(name=wf_name) # FSL part for the transformation matrix analysisflow.connect(inputspec, 'brain', linear_reg, 'in_file') analysisflow.connect(inputspec, 'reference_brain', linear_reg, 'reference') analysisflow.connect(linear_reg, 'out_matrix_file', inv_flirt_xfm, 'in_file') analysisflow.connect(inv_flirt_xfm, 'out_file', outputspec, 'invlinear_xfm') analysisflow.connect(inputspec, 'reference_skull', reg, 'reference_skull') analysisflow.connect(inputspec, 'reference_brain', reg, 'reference_brain') analysisflow.connect(inputspec, 'skull', reg, 'anatomical_skull') analysisflow.connect(inputspec, 'brain', reg, 'anatomical_brain') analysisflow.connect(reg, 'transform_composite', outputspec, 'nonlinear_xfm') analysisflow.connect(reg, 'transform_inverse_composite', outputspec, 'invnonlinear_xfm') analysisflow.connect(reg, 'warped_image', outputspec, 'output_brain') analysisflow.connect(reg, 'warped_image', ds, 'anat2mni_std') analysisflow.connect(reg, 'transform_composite', ds, 'anat2mni_warpfield') analysisflow.connect(reg, 'warped_image', myqc, 'inputspec.bg_image') return analysisflow
def fast_workflow(SinkTag="anat_preproc", wf_name="tissue_segmentation", priormap=True): """ Modified version of CPAC.seg_preproc.seg_preproc `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/seg_preproc/seg_preproc.html` Do the segmentation of a brain extracted T1w image. Workflow inputs: :param brain: The brain extracted image, the output of the better_workflow. :param init_transform: The standard to anat linear transformation matrix (which is calculated in the Anat2MNI.py script). Beware of the resolution of the reference (standard) image, the default value is 2mm. :param priorprob: A list of tissue probability maps in the prior (=reference=standard) space. By default it must be 3 element(in T1w images the CSF, GM, WM order is valid) :param SinkDir: :param SinkTag: The output directiry in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: fast_workflow - workflow Balint Kincses [email protected] 2018 """ #This is a Nipype generator. Warning, here be dragons. #!/usr/bin/env python import sys import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.interfaces.io as io import PUMI.utils.QC as qc import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) #Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=[ 'brain', 'stand2anat_xfm', # leave empty for no prior 'priorprob' ]), name='inputspec') # inputspec.inputs.stand2anat_xfm='/home/analyser/Documents/PAINTER/probewith2subj/preprocess_solvetodos/anat2mni_fsl/inv_linear_reg0_xfm/mapflow/_inv_linear_reg0_xfm0/anat_brain_flirt_inv.mat' #TODO_ready set standard mask to 2mm if priormap: inputspec.inputs.priorprob = [ globals._FSLDIR_ + '/data/standard/tissuepriors/avg152T1_csf.hdr', globals._FSLDIR_ + '/data/standard/tissuepriors/avg152T1_gray.hdr', globals._FSLDIR_ + '/data/standard/tissuepriors/avg152T1_white.hdr' ] # TODO_ready: use prior probabilioty maps # Wraps command **fast** if priormap: fast = pe.MapNode(interface=fsl.FAST(), iterfield=['in_files', 'init_transform'], name='fast') else: fast = pe.MapNode(interface=fsl.FAST(), iterfield=['in_files'], name='fast') fast.inputs.img_type = 1 fast.inputs.segments = True fast.inputs.probability_maps = True fast.inputs.out_basename = 'fast_' myqc = qc.vol2png("tissue_segmentation", overlay=False) myqc.inputs.slicer.colour_map = globals._FSLDIR_ + '/etc/luts/renderjet.lut' # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=[ 'probmap_csf', 'probmap_gm', 'probmap_wm', 'mixeltype', 'parvol_csf', 'parvol_gm', 'parvol_wm', 'partial_volume_map' ]), name='outputspec') # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] def pickindex(vec, i): #print "************************************************************************************************************************************************" #print vec #print i return [x[i] for x in vec] #Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.base_dir = '.' analysisflow.connect(inputspec, 'brain', fast, 'in_files') if priormap: analysisflow.connect(inputspec, 'stand2anat_xfm', fast, 'init_transform') #analysisflow.connect(inputspec, 'priorprob', fast,'other_priors') # commented out for compatibility with the original RPN-signature # analysisflow.connect(inputspec, 'stand_csf' ,fast,('other_priors', pickindex, 0)) # analysisflow.connect(inputspec, 'stand_gm' ,fast,('other_priors', pickindex, 1)) # analysisflow.connect(inputspec, 'stand_wm' ,fast,('other_priors', pickindex, 2)) #nalysisflow.connect(fast, 'probability_maps', outputspec, 'probability_maps') analysisflow.connect(fast, ('probability_maps', pickindex, 0), outputspec, 'probmap_csf') analysisflow.connect(fast, ('probability_maps', pickindex, 1), outputspec, 'probmap_gm') analysisflow.connect(fast, ('probability_maps', pickindex, 2), outputspec, 'probmap_wm') analysisflow.connect(fast, 'mixeltype', outputspec, 'mixeltype') #analysisflow.connect(fast, 'partial_volume_files', outputspec, 'partial_volume_files') analysisflow.connect(fast, ('partial_volume_files', pickindex, 0), outputspec, 'parvol_csf') analysisflow.connect(fast, ('partial_volume_files', pickindex, 0), outputspec, 'parvol_gm') analysisflow.connect(fast, ('partial_volume_files', pickindex, 0), outputspec, 'parvol_wm') analysisflow.connect(fast, 'partial_volume_map', outputspec, 'partial_volume_map') analysisflow.connect(fast, ('probability_maps', pickindex, 0), ds, 'fast_csf') analysisflow.connect(fast, ('probability_maps', pickindex, 1), ds, 'fast_gm') analysisflow.connect(fast, ('probability_maps', pickindex, 2), ds, 'fast_wm') analysisflow.connect(fast, 'partial_volume_map', myqc, 'inputspec.bg_image') return analysisflow
def mc_workflow_afni(reference_vol="mid", FD_mode="Power", SinkTag="func_preproc", wf_name="motion_correction_afni"): from nipype.interfaces.afni import preprocess import sys import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import PUMI.func_preproc.info.info_get as info_get import nipype.interfaces.io as io import nipype.algorithms.confounds as conf import PUMI.utils.utils_math as utils_math import PUMI.utils.utils_convert as utils_convert import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) QCDir = os.path.abspath(globals._SinkDir_ + "/" + globals._QCDir_) if not os.path.exists(QCDir): os.makedirs(QCDir) # Basic interface class generates identity mappings inputspec = pe.Node(utility.IdentityInterface( fields=['func', 'ref_vol', 'save_plots', 'stats_imgs']), name='inputspec') inputspec.inputs.save_plots = True inputspec.inputs.stats_imgs = True inputspec.inputs.ref_vol = reference_vol # extract reference volume refvol = pe.MapNode(utility.Function(input_names=['refvol', 'func'], output_names=['refvol'], function=getRefVol), iterfield=['func'], name='getRefVol') if (reference_vol == "mean"): func_motion_correct1 = pe.MapNode(interface=preprocess.Volreg(), iterfield=["in_file", "basefile"], name='mc_afni_init') func_motion_correct1.inputs.args = '-Fourier -twopass' func_motion_correct1.inputs.zpad = 4 func_motion_correct1.inputs.outputtype = 'NIFTI_GZ' # extract reference volume refvol2 = pe.MapNode(utility.Function(input_names=['refvol', 'func'], output_names=['refvol'], function=getRefVol), iterfield=['func'], name='getRefVol2') func_motion_correct = pe.MapNode(interface=preprocess.Volreg(), iterfield=["in_file", "basefile"], name='mc_afni') func_motion_correct.inputs.args = '-Fourier -twopass' func_motion_correct.inputs.zpad = 4 func_motion_correct.inputs.outputtype = 'NIFTI_GZ' myqc = qc.timecourse2png("timeseries", tag="010_motioncorr") # Calculate Friston24 parameters calc_friston = pe.MapNode(utility.Function( input_names=['in_file'], output_names=['out_file'], function=calc_friston_twenty_four), iterfield=['in_file'], name='calc_friston') if FD_mode == "Power": calculate_FD = pe.MapNode(conf.FramewiseDisplacement( parameter_source='AFNI', save_plot=True), iterfield=['in_file'], name='calculate_FD_Power') elif FD_mode == "Jenkinson": calculate_FD = pe.MapNode(utility.Function(input_names=['in_file'], output_names=['out_file'], function=calculate_FD_J), iterfield=['in_file'], name='calculate_FD_Jenkinson') # compute mean and max FD meanFD = pe.MapNode(interface=utils_math.Txt2meanTxt, iterfield=['in_file'], name='meanFD') meanFD.inputs.axis = 0 # global mean meanFD.inputs.header = True # global mean maxFD = pe.MapNode(interface=utils_math.Txt2maxTxt, iterfield=['in_file'], name='maxFD') maxFD.inputs.axis = 0 # global mean maxFD.inputs.header = True # global mean pop_FD = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_FD') pop_FDmax = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_FDmax') # save data out with Datasink ds_fd = pe.Node(interface=io.DataSink(), name='ds_pop_fd') ds_fd.inputs.regexp_substitutions = [("(\/)[^\/]*$", "FD.txt")] ds_fd.inputs.base_directory = SinkDir # save data out with Datasink ds_fd_max = pe.Node(interface=io.DataSink(), name='ds_pop_fd_max') ds_fd_max.inputs.regexp_substitutions = [("(\/)[^\/]*$", "FD_max.txt")] ds_fd_max.inputs.base_directory = SinkDir # Save outputs which are important ds_qc_fd = pe.Node(interface=io.DataSink(), name='ds_qc_fd') ds_qc_fd.inputs.base_directory = QCDir ds_qc_fd.inputs.regexp_substitutions = [("(\/)[^\/]*$", "_FD.pdf")] # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=[ 'func_out_file', 'first24_file', 'mat_file', 'mc_par_file', 'FD_file' ]), name='outputspec') # save data out with Datasink ds_nii = pe.Node(interface=io.DataSink(), name='ds_nii') ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] ds_nii.inputs.base_directory = SinkDir # save data out with Datasink ds_text = pe.Node(interface=io.DataSink(), name='ds_txt') ds_text.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".txt")] ds_text.inputs.base_directory = SinkDir # TODO_ready set the proper images which has to be saved in a the datasink specified directory # Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'func', refvol, 'func') analysisflow.connect(inputspec, 'ref_vol', refvol, 'refvol') if (reference_vol == "mean"): analysisflow.connect(inputspec, 'func', func_motion_correct1, 'in_file') analysisflow.connect(refvol, 'refvol', func_motion_correct1, 'basefile') analysisflow.connect(func_motion_correct1, 'out_file', refvol2, 'func') analysisflow.connect(inputspec, 'ref_vol', refvol2, 'refvol') analysisflow.connect(inputspec, 'func', func_motion_correct, 'in_file') analysisflow.connect(refvol2, 'refvol', func_motion_correct, 'basefile') else: analysisflow.connect(inputspec, 'func', func_motion_correct, 'in_file') analysisflow.connect(refvol, 'refvol', func_motion_correct, 'basefile') analysisflow.connect(func_motion_correct, 'oned_file', calc_friston, 'in_file') analysisflow.connect(func_motion_correct, 'oned_file', calculate_FD, 'in_file') analysisflow.connect(func_motion_correct, 'out_file', outputspec, 'func_out_file') analysisflow.connect(func_motion_correct, 'oned_matrix_save', outputspec, 'mat_file') analysisflow.connect(func_motion_correct, 'oned_file', outputspec, 'mc_par_file') analysisflow.connect(func_motion_correct, 'out_file', ds_nii, 'mc_func') analysisflow.connect(func_motion_correct, 'oned_file', ds_text, 'mc_par') # analysisflow.connect(func_motion_correct, 'variance_img', ds, 'mc.@variance_img') analysisflow.connect(calc_friston, 'out_file', outputspec, 'first24_file') analysisflow.connect(calc_friston, 'out_file', ds_text, 'mc_first24') analysisflow.connect(calculate_FD, 'out_file', outputspec, 'FD_file') analysisflow.connect(func_motion_correct, 'out_file', myqc, 'inputspec.func') # pop-level mean FD analysisflow.connect(calculate_FD, 'out_file', meanFD, 'in_file') analysisflow.connect(calculate_FD, 'out_file', ds_text, 'mc_fd') analysisflow.connect(meanFD, 'mean_file', pop_FD, 'in_list') analysisflow.connect(pop_FD, 'txt_file', ds_fd, 'pop') analysisflow.connect(calculate_FD, 'out_figure', ds_qc_fd, 'FD') analysisflow.connect(calculate_FD, 'out_file', maxFD, 'in_file') analysisflow.connect(maxFD, 'max_file', pop_FDmax, 'in_list') analysisflow.connect(pop_FDmax, 'txt_file', ds_fd_max, 'pop') return analysisflow
def anat2mni_ants_workflow_nipype(SinkTag="anat_preproc", wf_name="anat2mni_ants"): """ Register skull and brain extracted image to MNI space and return the transformation martices. Using ANTS, doing it in the nipype way. Workflow inputs: :param skull: The reoriented anatomical file. :param brain: The brain extracted anat. :param ref_skull: MNI152 skull file. :param ref_brain: MNI152 brain file. :param SinkDir: :param SinkTag: The output directiry in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: anat2mni_workflow - workflow anat="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres.nii.gz", brain="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres_brain.nii.gz", Tamas Spisak [email protected] 2018 """ SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Define inputs of workflow inputspec = pe.Node(utility.IdentityInterface( fields=['brain', 'skull', 'reference_brain', 'reference_skull']), name='inputspec') inputspec.inputs.reference_brain = globals._FSLDIR_ + globals._brainref #TODO_ready: 1 or 2mm??? inputspec.inputs.reference_skull = globals._FSLDIR_ + globals._headref # Multi-stage registration node with ANTS reg = pe.MapNode( interface=Registration(), iterfield=['moving_image'], # 'moving_image_mask'], name="ANTS") """ reg.inputs.transforms = ['Affine', 'SyN'] reg.inputs.transform_parameters = [(2.0,), (0.1, 3.0, 0.0)] reg.inputs.number_of_iterations = [[1500, 200], [100, 50, 30]] reg.inputs.dimension = 3 reg.inputs.write_composite_transform = True reg.inputs.collapse_output_transforms = False reg.inputs.initialize_transforms_per_stage = False reg.inputs.metric = ['Mattes', 'Mattes'] reg.inputs.metric_weight = [1] * 2 # Default (value ignored currently by ANTs) reg.inputs.radius_or_number_of_bins = [32] * 2 reg.inputs.sampling_strategy = ['Random', None] reg.inputs.sampling_percentage = [0.05, None] reg.inputs.convergence_threshold = [1.e-8, 1.e-9] reg.inputs.convergence_window_size = [20] * 2 reg.inputs.smoothing_sigmas = [[1, 0], [2, 1, 0]] reg.inputs.sigma_units = ['vox'] * 2 reg.inputs.shrink_factors = [[2, 1], [4, 2, 1]] reg.inputs.use_estimate_learning_rate_once = [True, True] reg.inputs.use_histogram_matching = [True, True] # This is the default reg.inputs.output_warped_image = 'output_warped_image.nii.gz' reg.inputs.winsorize_lower_quantile = 0.01 reg.inputs.winsorize_upper_quantile = 0.99 """ #satra says: reg.inputs.transforms = ['Rigid', 'Affine', 'SyN'] reg.inputs.transform_parameters = [(0.1, ), (0.1, ), (0.2, 3.0, 0.0)] reg.inputs.number_of_iterations = ([[10000, 111110, 11110]] * 2 + [[100, 50, 30]]) reg.inputs.dimension = 3 reg.inputs.write_composite_transform = True reg.inputs.collapse_output_transforms = True reg.inputs.initial_moving_transform_com = True reg.inputs.metric = ['Mattes'] * 2 + [['Mattes', 'CC']] reg.inputs.metric_weight = [1] * 2 + [[0.5, 0.5]] reg.inputs.radius_or_number_of_bins = [32] * 2 + [[32, 4]] reg.inputs.sampling_strategy = ['Regular'] * 2 + [[None, None]] reg.inputs.sampling_percentage = [0.3] * 2 + [[None, None]] reg.inputs.convergence_threshold = [1.e-8] * 2 + [-0.01] reg.inputs.convergence_window_size = [20] * 2 + [5] reg.inputs.smoothing_sigmas = [[4, 2, 1]] * 2 + [[1, 0.5, 0]] reg.inputs.sigma_units = ['vox'] * 3 reg.inputs.shrink_factors = [[3, 2, 1]] * 2 + [[4, 2, 1]] reg.inputs.use_estimate_learning_rate_once = [True] * 3 reg.inputs.use_histogram_matching = [False] * 2 + [True] reg.inputs.winsorize_lower_quantile = 0.005 reg.inputs.winsorize_upper_quantile = 0.995 reg.inputs.args = '--float' # Create png images for quality check myqc = qc.vol2png("anat2mni", "ANTS3", overlayiterated=False) myqc.inputs.inputspec.overlay_image = globals._FSLDIR_ + globals._brainref #TODO_ready: 1 or 2mm??? myqc.inputs.slicer.image_width = 500 # 5000 # for the 1mm template myqc.inputs.slicer.threshold_edges = 0.1 # 0.1 # for the 1mm template # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds_nii') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # Define outputs of the workflow outputspec = pe.Node(utility.IdentityInterface(fields=[ 'output_brain', 'linear_xfm', 'invlinear_xfm', 'nonlinear_xfm', 'invnonlinear_xfm', 'std_template' ]), name='outputspec') outputspec.inputs.std_template = inputspec.inputs.reference_brain # Create workflow nad connect nodes analysisflow = pe.Workflow(name=wf_name) analysisflow.connect(inputspec, 'reference_skull', reg, 'fixed_image') #analysisflow.connect(inputspec, 'reference_brain', reg, 'fixed_image_mask') analysisflow.connect(inputspec, 'skull', reg, 'moving_image') #analysisflow.connect(inputspec, 'brain', reg, 'moving_image_mask') analysisflow.connect(reg, 'composite_transform', outputspec, 'nonlinear_xfm') analysisflow.connect(reg, 'inverse_composite_transform', outputspec, 'invnonlinear_xfm') analysisflow.connect(reg, 'warped_image', outputspec, 'output_brain') analysisflow.connect(reg, 'warped_image', ds, 'anat2mni_std') analysisflow.connect(reg, 'composite_transform', ds, 'anat2mni_warpfield') analysisflow.connect(reg, 'warped_image', myqc, 'inputspec.bg_image') return analysisflow
def func2mni(stdreg, carpet_plot="", wf_name='func2mni', SinkTag="func_preproc"): """ stdreg: either globals._RegType_.ANTS or globals._RegType_.FSL (do default value to make sure the user has to decide explicitly) Transaform 4D functional image to MNI space. carpet_plot: string specifying the tag parameter for carpet plot of the standardized MRI measurement (default is "": no carpet plot) if not "", inputs atlaslabels and confounds should be defined (it might work with defaults, though) Workflow inputs: :param func :param linear_reg_mtrx :param nonlinear_reg_mtrx :param reference_brain :param atlas (optional) :param confounds (optional) :param confound_names (optional) Workflow outputs: :return: anat2mni_workflow - workflow anat="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres.nii.gz", brain="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres_brain.nii.gz", Balint Kincses [email protected] 2018 """ import os import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.interfaces.fsl as fsl import nipype.interfaces.ants as ants from nipype.interfaces.c3 import C3dAffineTool import PUMI.utils.globals as globals import PUMI.func_preproc.Onevol as onevol import PUMI.utils.QC as qc import nipype.interfaces.io as io from nipype.interfaces.utility import Function SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) inputspec = pe.Node( utility.IdentityInterface(fields=[ 'func', 'anat', # only obligatory if stdreg==globals._RegType_.ANTS 'linear_reg_mtrx', 'nonlinear_reg_mtrx', 'reference_brain', 'atlas', 'confounds', 'confound_names' ]), name='inputspec') inputspec.inputs.atlas = globals._FSLDIR_ + '/data/atlases/HarvardOxford/HarvardOxford-cort-maxprob-thr25-2mm.nii.gz' inputspec.inputs.reference_brain = globals._FSLDIR_ + "/data/standard/MNI152_T1_3mm_brain.nii.gz" #3mm by default # TODO: this does not work with the iterfiled definition for ref_file below: # TODO: it should be sepcified in a function argument, whether it shopuld be iterated #TODO_ready: ANTS #TODO: make resampling voxel size for func parametrizable # apply transformation martices if stdreg == globals._RegType_.FSL: applywarp = pe.MapNode(interface=fsl.ApplyWarp(interp="spline", ), iterfield=['in_file', 'field_file', 'premat'], name='applywarp') myqc = qc.vol2png("func2mni", wf_name + "_FSL", overlayiterated=False) myqc.inputs.slicer.image_width = 500 # 500 # for the 2mm template myqc.inputs.slicer.threshold_edges = 0.1 # 0.1 # for the 2mm template else: #ANTs # source file for C3dAffineToolmust not be 4D, so we extract the one example vol myonevol = onevol.onevol_workflow() # concat premat and ants transform bbr2ants = pe.MapNode( interface=C3dAffineTool(fsl2ras=True, itk_transform=True), iterfield=['source_file', 'transform_file', 'reference_file'], # output: 'itk_transform' name="bbr2ants") #concat trfs into a list trflist = pe.MapNode(interface=Function( input_names=['trf_first', 'trf_second'], output_names=['trflist'], function=transformlist), iterfield=['trf_first', 'trf_second'], name="collect_trf") applywarp = pe.MapNode(interface=ants.ApplyTransforms( interpolation="BSpline", input_image_type=3), iterfield=['input_image', 'transforms'], name='applywarp') myqc = qc.vol2png("func2mni", wf_name + "_ANTS3", overlayiterated=False) myqc.inputs.slicer.image_width = 500 # 500 # for the 2mm template myqc.inputs.slicer.threshold_edges = 0.1 # 0.1 # for the 2mm template if carpet_plot: fmri_qc = qc.fMRI2QC("carpet_plots", tag=carpet_plot) outputspec = pe.Node(utility.IdentityInterface(fields=['func_std']), name='outputspec') # Save outputs which are important ds_nii = pe.Node(interface=io.DataSink(), name='ds_nii') ds_nii.inputs.base_directory = SinkDir ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", wf_name + ".nii.gz")] analysisflow = pe.Workflow(wf_name) analysisflow.base_dir = '.' if stdreg == globals._RegType_.FSL: analysisflow.connect(inputspec, 'func', applywarp, 'in_file') analysisflow.connect(inputspec, 'linear_reg_mtrx', applywarp, 'premat') analysisflow.connect(inputspec, 'nonlinear_reg_mtrx', applywarp, 'field_file') analysisflow.connect(inputspec, 'reference_brain', applywarp, 'ref_file') analysisflow.connect(applywarp, 'out_file', outputspec, 'func_std') analysisflow.connect(applywarp, 'out_file', myqc, 'inputspec.bg_image') analysisflow.connect(inputspec, 'reference_brain', myqc, 'inputspec.overlay_image') analysisflow.connect(applywarp, 'out_file', ds_nii, 'func2mni') else: # ANTs analysisflow.connect(inputspec, 'func', myonevol, 'inputspec.func') analysisflow.connect(myonevol, 'outputspec.func1vol', bbr2ants, 'source_file') analysisflow.connect(inputspec, 'linear_reg_mtrx', bbr2ants, 'transform_file') analysisflow.connect(inputspec, 'anat', bbr2ants, 'reference_file') analysisflow.connect(bbr2ants, 'itk_transform', trflist, 'trf_first') analysisflow.connect(inputspec, 'nonlinear_reg_mtrx', trflist, 'trf_second') analysisflow.connect(trflist, 'trflist', applywarp, 'transforms') analysisflow.connect(inputspec, 'func', applywarp, 'input_image') analysisflow.connect(inputspec, 'reference_brain', applywarp, 'reference_image') analysisflow.connect(applywarp, 'output_image', outputspec, 'func_std') analysisflow.connect(applywarp, 'output_image', myqc, 'inputspec.bg_image') analysisflow.connect(inputspec, 'reference_brain', myqc, 'inputspec.overlay_image') analysisflow.connect(applywarp, 'output_image', ds_nii, 'func2mni') if carpet_plot: if stdreg == globals._RegType_.FSL: analysisflow.connect(applywarp, 'out_file', fmri_qc, 'inputspec.func') else: # ANTs analysisflow.connect(applywarp, 'output_image', fmri_qc, 'inputspec.func') analysisflow.connect(inputspec, 'atlas', fmri_qc, 'inputspec.atlas') analysisflow.connect(inputspec, 'confounds', fmri_qc, 'inputspec.confounds') return analysisflow
def compcor_workflow(SinkTag="func_preproc", wf_name="compcor"): """ `source: -` Component based noise reduction method (Behzadi et al.,2007): Regressing out principal components from noise ROIs. Here the aCompCor is used. Workflow inputs: :param func_aligned: The reoriented and realigned functional image. :param mask_files: Mask files which determine ROI(s). The default mask is the :param components_file :param num_componenets: :param pre_filter: Detrend time series prior to component extraction. :param TR :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow. Workflow outputs: :return: slt_workflow - workflow Balint Kincses [email protected] 2018 """ import os import nipype import nipype.pipeline as pe import nipype.algorithms.confounds as cnf import PUMI.func_preproc.info.info_get as info_get import PUMI.utils.utils_convert as utils_convert import nipype.interfaces.io as io import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import PUMI.utils.QC as qc import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=['func_aligned', 'mask_file']), name='inputspec') myqc = qc.vol2png("compcor_noiseroi") # Save outputs which are important ds_nii = pe.Node(interface=io.DataSink(), name='ds_nii') ds_nii.inputs.base_directory = SinkDir ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # standardize timeseries prior to compcor. added by tspisak scale = pe.MapNode(interface=utility.Function(input_names=['in_file'], output_names=['scaled_file'], function=scale_vol), iterfield=['in_file'], name='scale_func') # Calculate compcor files compcor = pe.MapNode( interface=cnf.ACompCor(pre_filter='polynomial', header_prefix="", num_components=5), iterfield=['realigned_file', 'repetition_time', 'mask_files'], name='compcor') # Custom interface wrapping function Float2Str func_str2float = pe.MapNode(interface=utils_convert.Str2Float, iterfield=['str'], name='func_str2float') # Drop first line of the Acompcor function output drop_firstline = pe.MapNode(interface=utils_convert.DropFirstLine, iterfield=['txt'], name='drop_firstline') # Custom interface wrapping function TR TRvalue = pe.MapNode(interface=info_get.TR, iterfield=['in_file'], name='TRvalue') # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=['components_file']), name='outputspec') # save data out with Datasink ds_text = pe.Node(interface=io.DataSink(), name='ds_txt') ds_text.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".txt")] ds_text.inputs.base_directory = SinkDir # Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'func_aligned', scale, 'in_file') analysisflow.connect(scale, 'scaled_file', compcor, 'realigned_file') analysisflow.connect(inputspec, 'func_aligned', TRvalue, 'in_file') analysisflow.connect(TRvalue, 'TR', func_str2float, 'str') analysisflow.connect(func_str2float, 'float', compcor, 'repetition_time') #analysisflow.connect(TRvalue, 'TR', compcor, 'repetition_time') analysisflow.connect(inputspec, 'mask_file', compcor, 'mask_files') analysisflow.connect(compcor, 'components_file', drop_firstline, 'txt') analysisflow.connect(drop_firstline, 'droppedtxtfloat', outputspec, 'components_file') analysisflow.connect(compcor, 'components_file', ds_text, 'compcor_noise') analysisflow.connect(inputspec, 'func_aligned', myqc, 'inputspec.bg_image') analysisflow.connect(inputspec, 'mask_file', myqc, 'inputspec.overlay_image') analysisflow.connect(inputspec, 'mask_file', ds_nii, 'compcor_noise_mask') return analysisflow
def aroma_workflow(fwhm=0, # in mm SinkTag = "func_preproc", wf_name="ICA_AROMA"): """ ICA AROMA method embedded into PUMI https://github.com/rhr-pruim/ICA-AROMA function input: fwhm: smoothing FWHM in mm. fwhm=0 means no smoothing Workflow inputs: :param mc_func: The reoriented and motion-corrected functional file. :param mc_params: motion parameters file from mcflirt :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow.. Workflow outputs: :return: aroma_workflow - workflow Tamas Spisak [email protected] 2018 """ from nipype.interfaces.fsl import ICA_AROMA import nipype.pipeline as pe from nipype.interfaces import utility import nipype.interfaces.io as io import PUMI.utils.QC as qc from nipype.interfaces.fsl import Smooth import os import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Define inputs of the workflow inputspec = pe.Node(utility.IdentityInterface(fields=['mc_func', 'mc_par', 'fnirt_warp_file', 'mat_file', 'mask', 'qc_mask' ]), name='inputspec') # build the actual pipeline if fwhm != 0: smoother = pe.MapNode(interface=Smooth(fwhm=fwhm), iterfield=['in_file'], name="smoother") myqc_before = qc.timecourse2png("timeseries", tag="1_original") aroma = pe.MapNode(interface=ICA_AROMA(denoise_type='both'), iterfield=['in_file', 'motion_parameters', 'mat_file', 'fnirt_warp_file', 'mask'], name="ICA_AROMA") aroma.inputs.denoise_type = 'both' aroma.inputs.out_dir = 'AROMA_out' myqc_after_nonaggr = qc.timecourse2png("timeseries", tag="2_nonaggressive") myqc_after_aggr = qc.timecourse2png("timeseries", tag="3_aggressive") # put these in the same QC dir getMotICs=pe.MapNode(interface=Function(input_names=['aroma_dir'], output_names=['motion_ICs'], function=extract_motionICs), iterfield=['aroma_dir'], name="get_motion_ICs") # Save outputs which are important ds_nii = pe.Node(interface=io.DataSink(), name='ds_nii') ds_nii.inputs.base_directory = SinkDir ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] ds_txt = pe.Node(interface=io.DataSink(), name='ds_txt') ds_txt.inputs.base_directory = SinkDir ds_txt.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".txt")] # Define outputs of the workflow outputspec = pe.Node(utility.IdentityInterface(fields=['aggr_denoised_file', 'nonaggr_denoised_file', 'motion_ICs', 'out_dir', 'fwhm']), name='outputspec') outputspec.inputs.fwhm = fwhm analysisflow = pe.Workflow(name=wf_name) if fwhm != 0: analysisflow.connect(inputspec, 'mc_func', smoother, 'in_file') analysisflow.connect(smoother, 'smoothed_file', aroma, 'in_file') analysisflow.connect(smoother, 'smoothed_file', myqc_before, 'inputspec.func') else: analysisflow.connect(inputspec, 'mc_func', aroma, 'in_file') analysisflow.connect(inputspec, 'mc_func', myqc_before, 'inputspec.func') analysisflow.connect(inputspec, 'mc_par', aroma, 'motion_parameters') analysisflow.connect(inputspec, 'mat_file', aroma, 'mat_file') analysisflow.connect(inputspec, 'fnirt_warp_file', aroma, 'fnirt_warp_file') analysisflow.connect(inputspec, 'mask', aroma, 'mask') analysisflow.connect(aroma, 'out_dir', getMotICs, 'aroma_dir') analysisflow.connect(getMotICs, 'motion_ICs', ds_txt, 'motion_ICs') analysisflow.connect(aroma, 'aggr_denoised_file', ds_nii, 'AROMA_aggr_denoised') analysisflow.connect(aroma, 'nonaggr_denoised_file', ds_nii, 'AROMA_nonaggr_denoised') analysisflow.connect(inputspec, 'qc_mask', myqc_before, 'inputspec.mask') analysisflow.connect(aroma, 'aggr_denoised_file', myqc_after_aggr, 'inputspec.func') #analysisflow.connect(inputspec, 'qc_mask', myqc_after_aggr, 'inputspec.mask') analysisflow.connect(aroma, 'nonaggr_denoised_file', myqc_after_nonaggr, 'inputspec.func') #analysisflow.connect(inputspec, 'qc_mask', myqc_after_nonaggr, 'inputspec.mask') analysisflow.connect(aroma, 'aggr_denoised_file', outputspec, 'aggr_denoised_file') analysisflow.connect(aroma, 'nonaggr_denoised_file', outputspec, 'nonaggr_denoised_file') analysisflow.connect(aroma, 'out_dir', outputspec, 'out_dir') analysisflow.connect(getMotICs, 'motion_ICs', outputspec, 'motion_ICs') return analysisflow
def datacens_workflow_threshold(SinkTag="func_preproc", wf_name="data_censoring", ex_before=1, ex_after=2): """ Modified version of CPAC.scrubbing.scrubbing + CPAC.generate_motion_statistics.generate_motion_statistics + CPAC.func_preproc.func_preproc `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/scrubbing/scrubbing.html` `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/generate_motion_statistics/generate_motion_statistics.html` `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/func_preproc/func_preproc.html` Description: Do the data censoring on the 4D functional data. First, it calculates the framewise displacement according to Power's method. Second, it indexes the volumes which FD is in the upper part in percent(determined by the threshold variable which is 5% by default). Thirdly, it excludes those volumes and one volume before and 2 volumes after the indexed volume. The workflow returns a 4D scrubbed functional data. Workflow inputs: :param func: The reoriented,motion occrected, nuissance removed and bandpass filtered functional file. :param FD: the frame wise displacement calculated by the MotionCorrecter.py script :param threshold: threshold of FD volumes which should be excluded :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow.. Workflow outputs: :return: datacens_workflow - workflow Balint Kincses [email protected] 2018 References ---------- .. [1] Power, J. D., Barnes, K. A., Snyder, A. Z., Schlaggar, B. L., & Petersen, S. E. (2012). Spurious but systematic correlations in functional connectivity MRI networks arise from subject motion. NeuroImage, 59(3), 2142-2154. doi:10.1016/j.neuroimage.2011.10.018 .. [2] Power, J. D., Barnes, K. A., Snyder, A. Z., Schlaggar, B. L., & Petersen, S. E. (2012). Steps toward optimizing motion artifact removal in functional connectivity MRI; a reply to Carp. NeuroImage. doi:10.1016/j.neuroimage.2012.03.017 .. [3] Jenkinson, M., Bannister, P., Brady, M., Smith, S., 2002. Improved optimization for the robust and accurate linear registration and motion correction of brain images. Neuroimage 17, 825-841. """ import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.io as io import PUMI.utils.utils_convert as utils_convert import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Identitiy mapping for input variables inputspec = pe.Node( utility.IdentityInterface(fields=['func', 'FD', 'threshold']), name='inputspec') inputspec.inputs.threshold = 0.2 #mm #TODO_ready check CPAC.generate_motion_statistics.generate_motion_statistics script. It may use the FD of Jenkinson to index volumes which violate the upper threhold limit, no matter what we set. # - we use the power method to calculate FD above_thr = pe.MapNode(utility.Function( input_names=['in_file', 'threshold', 'frames_before', 'frames_after'], output_names=[ 'frames_in_idx', 'frames_out_idx', 'percentFD', 'percent_scrubbed_file', 'fd_scrubbed_file', 'nvol' ], function=above_threshold), iterfield=['in_file'], name='above_threshold') above_thr.inputs.frames_before = ex_before above_thr.inputs.frames_after = ex_after # Save outputs which are important ds_fd_scrub = pe.Node(interface=io.DataSink(), name='ds_fd_scrub') ds_fd_scrub.inputs.base_directory = SinkDir ds_fd_scrub.inputs.regexp_substitutions = [("(\/)[^\/]*$", "FD_scrubbed.csv")] pop_perc_scrub = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_perc_scrub') # save data out with Datasink ds_pop_perc_scrub = pe.Node(interface=io.DataSink(), name='ds_pop_perc_scrub') ds_pop_perc_scrub.inputs.regexp_substitutions = [ ("(\/)[^\/]*$", "pop_percent_scrubbed.txt") ] ds_pop_perc_scrub.inputs.base_directory = SinkDir # Generate the weird input for the scrubbing procedure which is done in afni craft_scrub_input = pe.MapNode( utility.Function(input_names=['scrub_input', 'frames_in_1D_file'], output_names=['scrub_input_string'], function=get_indx), iterfield=['scrub_input', 'frames_in_1D_file'], name='scrubbing_craft_input_string') # Scrub the image scrubbed_preprocessed = pe.MapNode(utility.Function( input_names=['scrub_input'], output_names=['scrubbed_image'], function=scrub_image), iterfield=['scrub_input'], name='scrubbed_preprocessed') myqc = qc.timecourse2png("timeseries", tag="040_censored") outputspec = pe.Node( utility.IdentityInterface(fields=['scrubbed_image', 'FD_scrubbed']), name='outputspec') # save data out with Datasink ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir #TODO_ready: some plot for qualitiy checking # Create workflow analysisflow = pe.Workflow(wf_name) ###Calculating mean Framewise Displacement (FD) as Power et al., 2012 # Calculating frames to exclude and include after scrubbing analysisflow.connect(inputspec, 'FD', above_thr, 'in_file') analysisflow.connect(inputspec, 'threshold', above_thr, 'threshold') # Create the proper format for the scrubbing procedure analysisflow.connect(above_thr, 'frames_in_idx', craft_scrub_input, 'frames_in_1D_file') analysisflow.connect( above_thr, 'percent_scrubbed_file', ds, 'percentFD') # TODO save this in separate folder for QC analysisflow.connect(inputspec, 'func', craft_scrub_input, 'scrub_input') # Do the scubbing analysisflow.connect(craft_scrub_input, 'scrub_input_string', scrubbed_preprocessed, 'scrub_input') # Output analysisflow.connect(scrubbed_preprocessed, 'scrubbed_image', outputspec, 'scrubbed_image') analysisflow.connect(above_thr, 'fd_scrubbed_file', outputspec, 'FD_scrubbed') #TODO_ready: scrub FD file, as well analysisflow.connect(above_thr, 'fd_scrubbed_file', ds_fd_scrub, 'FD_scrubbed') analysisflow.connect(above_thr, 'percent_scrubbed_file', pop_perc_scrub, 'in_list') analysisflow.connect(pop_perc_scrub, 'txt_file', ds_pop_perc_scrub, 'pop') # Save a few files analysisflow.connect(scrubbed_preprocessed, 'scrubbed_image', ds, 'scrubbed_image') #analysisflow.connect(above_thr, 'percentFD', ds, 'scrubbed_image.@numberofvols') analysisflow.connect(scrubbed_preprocessed, 'scrubbed_image', myqc, 'inputspec.func') return analysisflow
datagrab.inputs.template = "*" # do we need this? datagrab.inputs.field_template = dict(struct=sys.argv[1]) # specified by command line arguments datagrab.inputs.sort_filelist = True reorient_struct = pe.MapNode(fsl.utils.Reorient2Std(), iterfield=['in_file'], name="reorient_struct") bet = pe.MapNode(interface=fsl.BET(), iterfield=['in_file'], iterables=[('vertical_gradient',[-0.2,0,0.2]) ], name='bet') myqc = qc.vol2png("brain_extraction", overlay=True) totalWorkflow = nipype.Workflow('bet_probe') totalWorkflow.base_dir = '.' totalWorkflow.connect([ (datagrab,reorient_struct, [('struct','in_file')]), (reorient_struct, bet, [('out_file', 'in_file')]), (bet,myqc, [('out_file', 'inputspec.overlay_image')]), (reorient_struct, myqc, [('out_file','inputspec.bg_image')]) ])
def FuncProc_despike_afni(stdrefvol="mid", SinkTag="func_preproc", wf_name="func_preproc_dspk_afni", fwhm=0, carpet_plot=""): """ Performs processing of functional (resting-state) images: Images should be already reoriented, e.g. with fsl fslreorient2std (see scripts/ex_pipeline.py) Workflow inputs: :param func: The functional image file. :param SinkDir: where to write important ouputs :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found. Workflow outputs: :param :return: anatproc_workflow Tamas Spisak [email protected] 2018 """ SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) wf_mc = nipype.Workflow(wf_name) # Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=['func', 'cc_noise_roi']), name='inputspec') # build the actual pipeline #myonevol = onevol.onevol_workflow(SinkDir=SinkDir) mybet = bet.bet_workflow(SinkTag="func_preproc", fmri=True, wf_name="brain_extraction_func") mymc = mc.mc_workflow_fsl(reference_vol=stdrefvol) if carpet_plot: # create "atlas" add_masks = pe.MapNode(fsl.ImageMaths(op_string=' -add'), iterfield=['in_file', 'in_file2'], name="addimgs") wf_mc.connect(inputspec, 'cc_noise_roi', add_masks, 'in_file') wf_mc.connect(mybet, 'outputspec.brain_mask', add_masks, 'in_file2') fmri_qc_mc = qc.fMRI2QC(carpet_plot, tag="mc", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc, 'inputspec.atlas') wf_mc.connect(mymc, 'outputspec.FD_file', fmri_qc_mc, 'inputspec.confounds') wf_mc.connect(mymc, 'outputspec.func_out_file', fmri_qc_mc, 'inputspec.func') mydespike = pe.MapNode( afni.Despike( outputtype="NIFTI_GZ"), # I do it after motion correction... iterfield=['in_file'], name="DeSpike") if carpet_plot: fmri_qc_mc_dspk = qc.fMRI2QC(carpet_plot, tag="mc_dspk", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc_dspk, 'inputspec.atlas') wf_mc.connect(mymc, 'outputspec.FD_file', fmri_qc_mc_dspk, 'inputspec.confounds') wf_mc.connect(mydespike, 'out_file', fmri_qc_mc_dspk, 'inputspec.func') mycmpcor = cmpcor.compcor_workflow() # to WM+CSF signal myconc = conc.concat_workflow(numconcat=2) mynuisscor = nuisscorr.nuissremov_workflow( ) # regress out 5 compcor variables and the Friston24 if carpet_plot: fmri_qc_mc_dspk_nuis = qc.fMRI2QC(carpet_plot, tag="mc_dspk_nuis", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc_dspk_nuis, 'inputspec.atlas') wf_mc.connect(mymc, 'outputspec.FD_file', fmri_qc_mc_dspk_nuis, 'inputspec.confounds') wf_mc.connect(mynuisscor, 'outputspec.out_file', fmri_qc_mc_dspk_nuis, 'inputspec.func') # optional smoother: if fwhm > 0: smoother = pe.MapNode(interface=Smooth(fwhm=fwhm), iterfield=['in_file'], name="smoother") if carpet_plot: fmri_qc_mc_dspk_smooth_nuis_bpf = qc.fMRI2QC( carpet_plot, tag="mc_dspk_nuis_smooth", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc_dspk_smooth_nuis_bpf, 'inputspec.atlas') wf_mc.connect(mymc, 'outputspec.FD_file', fmri_qc_mc_dspk_smooth_nuis_bpf, 'inputspec.confounds') wf_mc.connect(smoother, 'smoothed_file', fmri_qc_mc_dspk_smooth_nuis_bpf, 'inputspec.func') #mymedangcor = medangcor.mac_workflow() #skip it this time mytmpfilt = tmpfilt.tmpfilt_workflow( highpass_Hz=0.008, lowpass_Hz=0.08) #will be done by the masker? if carpet_plot: fmri_qc_mc_dspk_nuis_bpf = qc.fMRI2QC(carpet_plot, tag="mc_dspk_nuis_bpf", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc_dspk_nuis_bpf, 'inputspec.atlas') wf_mc.connect(mymc, 'outputspec.FD_file', fmri_qc_mc_dspk_nuis_bpf, 'inputspec.confounds') wf_mc.connect(mytmpfilt, 'outputspec.func_tmplfilt', fmri_qc_mc_dspk_nuis_bpf, 'inputspec.func') myscrub = scrub.datacens_workflow_threshold(ex_before=0, ex_after=0) # "liberal scrubbing" since despiking was already performed if carpet_plot: fmri_qc_mc_dspk_nuis_bpf_scrub = qc.fMRI2QC( carpet_plot, tag="mc_dspk_nuis_bpf_scrub", indiv_atlas=True) wf_mc.connect(add_masks, 'out_file', fmri_qc_mc_dspk_nuis_bpf_scrub, 'inputspec.atlas') wf_mc.connect(myscrub, 'outputspec.FD_scrubbed', fmri_qc_mc_dspk_nuis_bpf_scrub, 'inputspec.confounds') wf_mc.connect(myscrub, 'outputspec.scrubbed_image', fmri_qc_mc_dspk_nuis_bpf_scrub, 'inputspec.func') # Basic interface class generates identity mappings outputspec = pe.Node( utility.IdentityInterface(fields=[ 'func_preprocessed', 'func_preprocessed_scrubbed', # non-image data 'FD' ]), name='outputspec') wf_mc.connect([ (inputspec, mybet, [('func', 'inputspec.in_file')]), (mybet, mymc, [('outputspec.brain', 'inputspec.func')]), (mymc, mydespike, [('outputspec.func_out_file', 'in_file')]), (mydespike, mycmpcor, [('out_file', 'inputspec.func_aligned')]), (inputspec, mycmpcor, [('cc_noise_roi', 'inputspec.mask_file')]), (mycmpcor, myconc, [('outputspec.components_file', 'inputspec.par1')]), (mymc, myconc, [('outputspec.first24_file', 'inputspec.par2')]), (myconc, mynuisscor, [('outputspec.concat_file', 'inputspec.design_file')]), (mydespike, mynuisscor, [('out_file', 'inputspec.in_file')]) ]) if fwhm > 0: wf_mc.connect([ (mynuisscor, smoother, [('outputspec.out_file', 'in_file')]), (smoother, mytmpfilt, [('smoothed_file', 'inputspec.func')]), (mytmpfilt, myscrub, [('outputspec.func_tmplfilt', 'inputspec.func')]), (mymc, myscrub, [('outputspec.FD_file', 'inputspec.FD')]), (mytmpfilt, outputspec, [('outputspec.func_tmplfilt', 'func_preprocessed')]) ]) else: wf_mc.connect([(mynuisscor, mytmpfilt, [('outputspec.out_file', 'inputspec.func')]), (mytmpfilt, myscrub, [('outputspec.func_tmplfilt', 'inputspec.func')]), (mymc, myscrub, [('outputspec.FD_file', 'inputspec.FD') ]), (mytmpfilt, outputspec, [('outputspec.func_tmplfilt', 'func_preprocessed')])]) wf_mc.connect([ # non-image data: (mymc, outputspec, [('outputspec.FD_file', 'FD')]), (myscrub, outputspec, [('outputspec.scrubbed_image', 'func_preprocessed_scrubbed')]), ]) return wf_mc
def fieldmapper(TE1=4.9, TE2=7.3, dwell_time=0.00035, unwarp_direction="y-", SinkTag="func_fieldmapcorr", wf_name="fieldmap_correction"): import os import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) ########################################### # HERE INSERT PORCUPINE GENERATED CODE # MUST DEFINE # OutJSON: file path to JSON file contaioning the output strings to be returned # variables can (should) use variable SinkDir (defined here as function argument) ########################################### # To do ########################################### # adjust number of cores with psutil.cpu_count() ########################################### # also subtract: # analysisflow = nipype.Workflow('FieldMapper') # analysisflow.base_dir = '.' ########################################### # Here comes the generated code ########################################### # This is a Nipype generator. Warning, here be dragons. # !/usr/bin/env python import sys import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import PUMI.utils.utils_math as utils_math import nipype.interfaces.io as io import PUMI.utils.QC as qc import PUMI.utils.utils_convert as utils_convert OutJSON = SinkDir + "/outputs.JSON" # Basic interface class generates identity mappings inputspec = pe.Node(utility.IdentityInterface(fields=[ 'in_file', 'magnitude', 'phase', 'TE1', 'TE2', 'dwell_time', 'unwarp_direction' ]), name='inputspec') #defaults: #inputspec.inputs.func = func #inputspec.inputs.magnitude = magnitude #inputspec.inputs.phase = phase inputspec.inputs.TE1 = TE1 inputspec.inputs.TE2 = TE2 inputspec.inputs.dwell_time = dwell_time inputspec.inputs.unwarp_direction = unwarp_direction # Wraps command **bet** bet = pe.MapNode(interface=fsl.BET(), name='bet', iterfield=['in_file']) bet.inputs.mask = True # Wraps command **fslmaths** erode = pe.MapNode(interface=fsl.ErodeImage(), name='erode', iterfield=['in_file']) # Wraps command **fslmaths** erode2 = pe.MapNode(interface=fsl.ErodeImage(), name='erode2', iterfield=['in_file']) # Custom interface wrapping function SubTwo subtract = pe.Node(interface=utils_math.SubTwo, name='subtract') # Custom interface wrapping function Abs abs = pe.Node(interface=utils_math.Abs, name='abs') # Wraps command **fsl_prepare_fieldmap** preparefm = pe.MapNode(interface=fsl.PrepareFieldmap(), name='preparefm', iterfield=['in_phase', 'in_magnitude']) # Wraps command **fugue** fugue = pe.MapNode(interface=fsl.FUGUE(), name='fugue', iterfield=['in_file', 'fmap_in_file', 'mask_file']) # Generic datasink module to store structured outputs outputspec = pe.Node(interface=io.DataSink(), name='outputspec') outputspec.inputs.base_directory = SinkDir outputspec.inputs.regexp_substitutions = [ ("func_fieldmapcorr/_NodeName_.{13}", "") ] # Generic datasink module to store structured outputs outputspec2 = pe.Node(interface=io.DataSink(), name='outputspec2') outputspec2.inputs.base_directory = SinkDir outputspec2.inputs.regexp_substitutions = [("_NodeName_.{13}", "")] myqc_orig = qc.vol2png("fielmap_correction", tag="original") myqc_unwarp = qc.vol2png("fielmap_correction", tag="unwarped") # Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.base_dir = '.' analysisflow.connect(preparefm, 'out_fieldmap', outputspec2, 'fieldmap') analysisflow.connect(abs, 'abs', preparefm, 'delta_TE') analysisflow.connect(subtract, 'dif', abs, 'x') analysisflow.connect(inputspec, 'unwarp_direction', fugue, 'unwarp_direction') analysisflow.connect(fugue, 'unwarped_file', outputspec, 'func_fieldmapcorr') analysisflow.connect(preparefm, 'out_fieldmap', fugue, 'fmap_in_file') analysisflow.connect(erode2, 'out_file', fugue, 'mask_file') analysisflow.connect(bet, 'mask_file', erode2, 'in_file') analysisflow.connect(inputspec, 'dwell_time', fugue, 'dwell_time') analysisflow.connect(inputspec, 'in_file', fugue, 'in_file') analysisflow.connect(bet, 'out_file', erode, 'in_file') analysisflow.connect(inputspec, 'TE2', subtract, 'b') analysisflow.connect(inputspec, 'TE1', subtract, 'a') analysisflow.connect(inputspec, 'phase', preparefm, 'in_phase') analysisflow.connect(erode, 'out_file', preparefm, 'in_magnitude') analysisflow.connect(inputspec, 'magnitude', bet, 'in_file') analysisflow.connect(inputspec, 'magnitude', myqc_orig, 'inputspec.bg_image') analysisflow.connect(inputspec, 'in_file', myqc_orig, 'inputspec.overlay_image') analysisflow.connect(inputspec, 'magnitude', myqc_unwarp, 'inputspec.bg_image') analysisflow.connect(fugue, 'unwarped_file', myqc_unwarp, 'inputspec.overlay_image') # Run the workflow #plugin = 'MultiProc' # adjust your desired plugin here #plugin_args = {'n_procs': psutil.cpu_count()} # adjust to your number of cores #analysisflow.write_graph(graph2use='flat', format='png', simple_form=False) #analysisflow.run(plugin=plugin, plugin_args=plugin_args) #################################################################################################### # Porcupine generated code ends here #################################################################################################### #load and return json # you have to be aware the keys of the json map here #ret = json.load(open(OutJSON)) #return ret['func_fieldmapcorr'], ret['fieldmap'] return analysisflow
iterfield=['in_file'], name='scale') #todo: parametrize fwhm myaroma = aroma.aroma_workflow(fwhm=8) func2std = func2standard.func2mni(stdreg=globals._RegType_.FSL, wf_name='func2std') func2std_aroma_nonaggr = func2standard.func2mni( stdreg=globals._RegType_.FSL, wf_name='func2std_aroma_nonaggr') func2std_aroma_nonaggr.inputs.inputspec.reference_brain = globals._FSLDIR_ + "/data/standard/MNI152_T1_3mm_brain.nii.gz" func2std_aroma_aggr = func2standard.func2mni(stdreg=globals._RegType_.FSL, wf_name='func2std_aroma_aggr') func2std_aroma_aggr.inputs.inputspec.reference_brain = globals._FSLDIR_ + "/data/standard/MNI152_T1_3mm_brain.nii.gz" fmri_qc_original = qc.fMRI2QC("carpet_aroma", tag="1_orinal") fmri_qc_nonaggr = qc.fMRI2QC("carpet_aroma", tag="2_nonaggressive") fmri_qc_aggr = qc.fMRI2QC("carpet_aroma", tag="3_aggressive") # compute mean FD meanFD = pe.MapNode(interface=utils_math.Txt2meanTxt, iterfield=['in_file'], name='meanFD') meanFD.inputs.axis = 0 # global mean pop_FD = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_FD') # TODO sink this pop_FD.inputs.rownum = 0 pop_FD.inputs.out_file = "FD.txt" totalWorkflow = nipype.Workflow('exAROMA')
def tmpfilt_workflow(highpass_Hz, lowpass_Hz, SinkTag="func_preproc", wf_name="temporal_filtering"): #TODO kivezetni a higpass_inseces lowpass_insec valtozokat egy(esetleg kettto)-vel feljebbi szintekre. """ Modified version of porcupine generated temporal filtering code: `source: -` Creates a slice time corrected functional image. Workflow inputs: :param func: The reoriented functional file. :param highpass: The highpass filter, which is 100s by default. :param lowpass: The lowpass filter, which is 1s by default. :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow. Workflow outputs: :return: tmpfilt_workflow - workflow Balint Kincses [email protected] 2018 """ #This is a Nipype generator. Warning, here be dragons. #!/usr/bin/env python import sys import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import PUMI.utils.utils_math as utils_math import PUMI.func_preproc.info.info_get as info_get import PUMI.utils.utils_convert as utils_convert import nipype.interfaces.fsl as fsl from nipype.interfaces import afni import nipype.interfaces.io as io import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) #Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=[ 'func' #'highpass_Hz', # TODO: make these available as input #'lowpass_Hz' ]), name='inputspec') #nputspec.inputs.highpass_HZ = highpass_Hz #inputspec.inputs.lowpass_Hz = lowpass_Hz #Custom interface wrapping function Sec2sigmaV #func_sec2sigmaV = pe.MapNode(interface = utils_math.Sec2sigmaV, # iterfield=['TR'], # name = 'func_sec2sigmaV') #Custom interface wrapping function Sec2sigmaV_2 #func_sec2sigmaV_2 = pe.MapNode(interface = utils_math.Sec2sigmaV, # iterfield=['TR'], # name = 'func_sec2sigmaV_2') # Custom interface wrapping function Str2Func func_str2float = pe.MapNode(interface=utils_convert.Str2Float, iterfield=['str'], name='func_str2float') #Wraps command **fslmaths** # TODO_done: change highpass filter to AFNI implewmentation: # https://neurostars.org/t/bandpass-filtering-different-outputs-from-fsl-and-nipype-custom-function/824 #tmpfilt = pe.MapNode(interface=fsl.TemporalFilter(), # iterfield=['in_file','highpass','lowpass'], # name = 'tmpfilt') tmpfilt = pe.MapNode(interface=afni.Bandpass(highpass=highpass_Hz, lowpass=lowpass_Hz), iterfield=['in_file', 'tr'], name='tmpfilt') tmpfilt.inputs.despike = False tmpfilt.inputs.no_detrend = False #True tmpfilt.inputs.notrans = True # hopefully there are no initial transients in our data tmpfilt.inputs.outputtype = 'NIFTI_GZ' # Get TR value from header TRvalue = pe.MapNode(interface=info_get.TR, iterfield=['in_file'], name='TRvalue') myqc = qc.timecourse2png("timeseries", tag="030_filtered_" + str(highpass_Hz).replace('0.', '') + "_" + str(lowpass_Hz).replace('0.', '') + "_Hz") #Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=['func_tmplfilt']), name='outputspec') #Generic datasink module to store structured outputs ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir #ds.inputs.regexp_substitutions = [("tmpfilt/_NodeName_.{13}", "")] #Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'func', tmpfilt, 'in_file') analysisflow.connect(inputspec, 'func', TRvalue, 'in_file') analysisflow.connect(TRvalue, 'TR', func_str2float, 'str') analysisflow.connect(func_str2float, 'float', tmpfilt, 'tr') #analysisflow.connect(inputspec, 'highpass_Hz', tmpfilt, 'highpass') #analysisflow.connect(inputspec, 'lowpass_Hz', tmpfilt, 'lowpass') analysisflow.connect(tmpfilt, 'out_file', ds, 'tmpfilt') analysisflow.connect(tmpfilt, 'out_file', outputspec, 'func_tmplfilt') analysisflow.connect(tmpfilt, 'out_file', myqc, 'inputspec.func') return analysisflow
def extract_timeseries_nativespace(SinkTag="connectivity", wf_name="extract_timeseries_nativespace", global_signal=True): # this workflow transforms atlas back to native space and uses TsExtractor import os import nipype import nipype.pipeline as pe import nipype.interfaces.io as io import nipype.interfaces.utility as utility import PUMI.func_preproc.func2standard as transform import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) wf = nipype.Workflow(wf_name) inputspec = pe.Node( utility.IdentityInterface(fields=[ 'atlas', 'labels', 'modules', 'anat', # only obligatory if stdreg==globals._RegType_.ANTS 'inv_linear_reg_mtrx', 'inv_nonlinear_reg_mtrx', 'func', 'gm_mask', 'confounds', 'confound_names' ]), name="inputspec") # transform atlas back to native EPI spaces! atlas2native = transform.atlas2func(stdreg=globals._regType_) wf.connect(inputspec, 'atlas', atlas2native, 'inputspec.atlas') wf.connect(inputspec, 'anat', atlas2native, 'inputspec.anat') wf.connect(inputspec, 'inv_linear_reg_mtrx', atlas2native, 'inputspec.inv_linear_reg_mtrx') wf.connect(inputspec, 'inv_nonlinear_reg_mtrx', atlas2native, 'inputspec.inv_nonlinear_reg_mtrx') wf.connect(inputspec, 'func', atlas2native, 'inputspec.func') wf.connect(inputspec, 'gm_mask', atlas2native, 'inputspec.example_func') wf.connect(inputspec, 'confounds', atlas2native, 'inputspec.confounds') wf.connect(inputspec, 'confound_names', atlas2native, 'inputspec.confound_names') # extract timeseries extract_timeseries = pe.MapNode(interface=utility.Function( input_names=['labels', 'labelmap', 'func', 'mask', 'global_signal'], output_names=['out_file', 'labels', 'out_gm_label'], function=TsExtractor), iterfield=['labelmap', 'func', 'mask'], name='extract_timeseries') extract_timeseries.inputs.global_signal = global_signal wf.connect(atlas2native, 'outputspec.atlas2func', extract_timeseries, 'labelmap') wf.connect(inputspec, 'labels', extract_timeseries, 'labels') wf.connect(inputspec, 'gm_mask', extract_timeseries, 'mask') wf.connect(inputspec, 'func', extract_timeseries, 'func') # Save outputs which are important ds_regts = pe.Node(interface=io.DataSink(), name='ds_regts') ds_regts.inputs.base_directory = globals._SinkDir_ ds_regts.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".tsv")] wf.connect(extract_timeseries, 'out_file', ds_regts, 'regional_timeseries') # QC timeseries_qc = qc.regTimeseriesQC("regional_timeseries", tag=wf_name) wf.connect(inputspec, 'modules', timeseries_qc, 'inputspec.modules') wf.connect(inputspec, 'atlas', timeseries_qc, 'inputspec.atlas') wf.connect(extract_timeseries, 'out_file', timeseries_qc, 'inputspec.timeseries') # Basic interface class generates identity mappings outputspec = pe.Node( utility.IdentityInterface(fields=['timeseries', 'out_gm_label']), name='outputspec') wf.connect(extract_timeseries, 'out_file', outputspec, 'timeseries') wf.connect(extract_timeseries, 'out_gm_label', outputspec, 'out_gm_label') return wf
def mac_workflow(target_angle=90, SinkTag="func_preproc", wf_name="median_angle_correction"): """ Modified version of CPAC.median_angle.median_angle: `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/median_angle/median_angle.html` Do the data censoring on the 4D functional data. Workflow inputs: :param func: The reoriented functional file. :param target angle: the default is 90. :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow.. Workflow outputs: :return: datacens_workflow - workflow Balint Kincses [email protected] 2018 Median Angle Correction Parameters ---------- name : string, optional Name of the workflow. Returns ------- median_angle_correction : nipype.pipeline.engine.Workflow Median Angle Correction workflow. Notes ----- Workflow Inputs:: inputspec.subject : string (nifti file) Realigned nifti file of a subject inputspec.target_angle : integer Target angle in degrees to correct the median angle to Workflow Outputs:: outputspec.subject : string (nifti file) Median angle corrected nifti file of the given subject outputspec.pc_angles : string (.npy file) Numpy file (.npy file) containing the angles (in radians) of all voxels with the 5 largest principal components. Median Angle Correction Procedure: 1. Compute the median angle with respect to the first principal component of the subject 2. Shift the angle of every voxel so that the new median angle equals the target angle Workflow Graph: .. image:: ../images/median_angle_correction.dot.png :width: 500 Detailed Workflow Graph: .. image:: ../images/median_angle_correction_detailed.dot.png :width: 500 """ import os import nipype.pipeline.engine as pe import nipype.interfaces.utility as utility import PUMI.utils.utils_convert as utils_convert import nipype.interfaces.io as io import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) #TODO set target angle... inputspec = pe.Node(utility.IdentityInterface( fields=['realigned_file', 'target_angle', 'mask']), name='inputspec') inputspec.inputs.target_angle = target_angle outputspec = pe.Node( utility.IdentityInterface(fields=['final_func', 'pc_angles']), name='outputspec') # Caution: inpout fmri must be masked (background=0) mac = pe.MapNode(utility.Function( input_names=['target_angle_deg', 'realigned_file', 'mask'], output_names=['corrected_file', 'angles_file'], function=median_angle_correct), iterfield=['realigned_file', 'mask'], name='median_angle_correct') myqc = qc.timecourse2png("timeseries", tag="050_medang") # collect and save median angle values pop_medang = pe.Node( interface=utils_convert. List2TxtFile, #TODO: save subject level median angle name='pop_medang') # save mac file ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # save data out with Datasink ds_medang = pe.Node(interface=io.DataSink(), name='ds_pop_medang') ds_medang.inputs.regexp_substitutions = [("(\/)[^\/]*$", "medang.txt")] ds_medang.inputs.base_directory = SinkDir #TODO set which files should be put into the datasink node... # Create workflow analysisflow = pe.Workflow(wf_name) analysisflow.connect(inputspec, 'realigned_file', mac, 'realigned_file') analysisflow.connect(inputspec, 'target_angle', mac, 'target_angle_deg') analysisflow.connect(inputspec, 'mask', mac, 'mask') analysisflow.connect(mac, 'corrected_file', outputspec, 'final_func') analysisflow.connect(mac, 'angles_file', outputspec, 'pc_angles') analysisflow.connect(mac, 'corrected_file', myqc, 'inputspec.func') # pop-level medang values analysisflow.connect(mac, 'angles_file', pop_medang, 'in_list') analysisflow.connect(pop_medang, 'txt_file', ds_medang, 'pop') analysisflow.connect(mac, 'corrected_file', ds, 'med_ang') return analysisflow
def build_netmat(SinkTag="connectivity", wf_name="build_network"): ######################################################################## # Extract timeseries ######################################################################## import nipype.pipeline as pe import nipype.interfaces.utility as utility from nipype.interfaces.utility import Function import nipype.interfaces.io as io import PUMI.utils.globals as globals import PUMI.utils.QC as qc import os SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Identitiy mapping for input variables inputspec = pe.Node( utility.IdentityInterface(fields=[ 'timeseries', #contains labels 'modules', # optional 'measure', 'atlas' # optional, only for plotting purposes ]), name='inputspec') inputspec.inputs.atlas = False # default value inputspec.inputs.measure = "partial correlation" # This is not a map node, since it takes all the subject-level regional timseries in a list and does population-level modelling # if measure == "tangent" estimate_network_mtx = pe.Node(interface=Function( input_names=['timeseries_list', 'modules', 'measure'], output_names=['mean_mtx', 'subject_matrix_list'], function=netmat), name='estimate_network_mtx') matrix_qc_mean = qc.matrixQC("group_mean_matrix", tag=wf_name + "_") matrix_qc = qc.matrixQC("matrices", tag=wf_name) # Save outputs which are important ds_meanmat = pe.Node(interface=io.DataSink(), name='ds_meanmat') ds_meanmat.inputs.base_directory = SinkDir ds_meanmat.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".tsv")] # Save outputs which are important ds_mat = pe.Node(interface=io.DataSink(), name='ds_mats') ds_mat.inputs.base_directory = SinkDir ds_mat.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".tsv")] analysisflow = pe.Workflow(wf_name) analysisflow.connect(inputspec, 'timeseries', estimate_network_mtx, 'timeseries_list') analysisflow.connect(inputspec, 'measure', estimate_network_mtx, 'measure') analysisflow.connect(estimate_network_mtx, 'mean_mtx', ds_meanmat, 'mean_connectivity_mat') analysisflow.connect(estimate_network_mtx, 'subject_matrix_list', ds_mat, 'connectivity_matrices') analysisflow.connect(estimate_network_mtx, 'mean_mtx', matrix_qc_mean, 'inputspec.matrix_file') analysisflow.connect(inputspec, 'modules', matrix_qc_mean, 'inputspec.modules') analysisflow.connect(inputspec, 'atlas', matrix_qc_mean, 'inputspec.atlas') analysisflow.connect(estimate_network_mtx, 'subject_matrix_list', matrix_qc, 'inputspec.matrix_file') analysisflow.connect(inputspec, 'modules', matrix_qc, 'inputspec.modules') analysisflow.connect(inputspec, 'atlas', matrix_qc, 'inputspec.atlas') return analysisflow
def nuissremov_workflow(SinkTag="func_preproc", wf_name="nuisance_correction"): """ The script uses the noise information to regress it out from the data. Workflow inputs: :param in_file: The reoriented an motion corrected functional data. :param desing_file: A matrix which contains all the nuissance regressor(motion+compcor noise+...). :param filter_all: To regress out all the columns of the desing matrix (default: True) :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow. Workflow outputs: :return: nuissremov_workflow Balint Kincses [email protected] 2018 """ import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.interfaces.io as io import PUMI.utils.QC as qc import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=['in_file', 'design_file']), name='inputspec') # Perform the nuissance regression nuisregression = pe.MapNode(interface=fsl.FilterRegressor(filter_all=True), iterfield=['design_file', 'in_file'], name='nuisregression') myqc = qc.timecourse2png("timeseries", tag="020_nuiscorr") # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=['out_file']), name='outputspec') # save data out with Datasink ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir #TODO_ready: qc timeseries before and after # Generate workflow analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'in_file', nuisregression, 'in_file') analysisflow.connect(inputspec, 'design_file', nuisregression, 'design_file') analysisflow.connect(nuisregression, 'out_file', outputspec, 'out_file') analysisflow.connect(nuisregression, 'out_file', ds, 'func_nuiss_corrected') analysisflow.connect(nuisregression, 'out_file', myqc, 'inputspec.func') return analysisflow
def bbr_workflow(SinkTag="func_preproc", wf_name="func2anat"): """ Modified version of CPAC.registration.registration: `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/registration/registration.html` BBR registration of functional image to anat. Workflow inputs: :param func: One volume of the 4D fMRI (The one which is the closest to the fieldmap recording in time should be chosen- e.g: if fieldmap was recorded after the fMRI the last volume of it should be chosen). :param skull: The oriented high res T1w image. :param anat_wm_segmentation: WM probability mask in . :param anat_csf_segmentation: CSF probability mask in :param bbr_schedule: Parameters which specifies BBR options. :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: bbreg_workflow - workflow func="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/s002/func_data.nii.gz", skull="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres.nii.gz", anat_wm_segmentation="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/anat_preproc/fast/fast__prob_2.nii.gz", Balint Kincses [email protected] 2018 """ import os import nipype.pipeline as pe from nipype.interfaces.utility import Function import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.interfaces.io as io import PUMI.func_preproc.Onevol as onevol import PUMI.utils.QC as qc import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Define inputs of the workflow inputspec = pe.Node(utility.IdentityInterface(fields=[ 'func', 'skull', 'anat_wm_segmentation', 'anat_gm_segmentation', 'anat_csf_segmentation', 'anat_ventricle_segmentation' ]), name='inputspec') myonevol = onevol.onevol_workflow() # trilinear interpolation is used by default in linear registration for func to anat linear_reg = pe.MapNode(interface=fsl.FLIRT(), iterfield=['in_file', 'reference'], name='linear_func_to_anat') linear_reg.inputs.cost = 'corratio' linear_reg.inputs.dof = 6 linear_reg.inputs.out_matrix_file = "lin_mat" # WM probability map is thresholded and masked wm_bb_mask = pe.MapNode(interface=fsl.ImageMaths(), iterfield=['in_file'], name='wm_bb_mask') wm_bb_mask.inputs.op_string = '-thr 0.5 -bin' # CSf probability map is thresholded and masked csf_bb_mask = pe.MapNode(interface=fsl.ImageMaths(), iterfield=['in_file'], name='csf_bb_mask') csf_bb_mask.inputs.op_string = '-thr 0.5 -bin' # GM probability map is thresholded and masked gm_bb_mask = pe.MapNode(interface=fsl.ImageMaths(), iterfield=['in_file'], name='gm_bb_mask') gm_bb_mask.inputs.op_string = '-thr 0.1 -bin' # liberal mask to capture all gm signal # ventricle probability map is thresholded and masked vent_bb_mask = pe.MapNode(interface=fsl.ImageMaths(), iterfield=['in_file'], name='vent_bb_mask') vent_bb_mask.inputs.op_string = '-thr 0.8 -bin -ero -dilM' # stricter threshold and some morphology for compcor # add the CSF and WM masks #add_masks=pe.MapNode(interface=fsl.ImageMaths(), # iterfield=['in_file','in_file2'], # name='add_masks') #add_masks.inputs.op_string = ' -add' # A function is defined for define bbr argumentum which says flirt to perform bbr registration # for each element of the list, due to MapNode def bbreg_args(bbreg_target): return '-cost bbr -wmseg ' + bbreg_target bbreg_arg_convert = pe.MapNode(interface=Function( input_names=["bbreg_target"], output_names=["arg"], function=bbreg_args), iterfield=['bbreg_target'], name="bbr_arg_converter") # BBR registration within the FLIRT node bbreg_func_to_anat = pe.MapNode( interface=fsl.FLIRT(), iterfield=['in_file', 'reference', 'in_matrix_file', 'args'], name='bbreg_func_to_anat') bbreg_func_to_anat.inputs.dof = 6 # calculate the inverse of the transformation matrix (of func to anat) convertmatrix = pe.MapNode(interface=fsl.ConvertXFM(), iterfield=['in_file'], name="convertmatrix") convertmatrix.inputs.invert_xfm = True # use the invers registration (anat to func) to transform anatomical csf mask reg_anatmask_to_func1 = pe.MapNode( interface=fsl.FLIRT(apply_xfm=True, interp='nearestneighbour'), iterfield=['in_file', 'reference', 'in_matrix_file'], name='anatmasks_to_func1') #reg_anatmask_to_func1.inputs.apply_xfm = True # use the invers registration (anat to func) to transform anatomical wm mask reg_anatmask_to_func2 = pe.MapNode( interface=fsl.FLIRT(apply_xfm=True, interp='nearestneighbour'), iterfield=['in_file', 'reference', 'in_matrix_file'], name='anatmasks_to_func2') #reg_anatmask_to_func2.inputs.apply_xfm = True # use the invers registration (anat to func) to transform anatomical gm mask reg_anatmask_to_func3 = pe.MapNode( interface=fsl.FLIRT(apply_xfm=True, interp='nearestneighbour'), iterfield=['in_file', 'reference', 'in_matrix_file'], name='anatmasks_to_func3') # reg_anatmask_to_func2.inputs.apply_xfm = True # use the invers registration (anat to func) to transform anatomical gm mask reg_anatmask_to_func4 = pe.MapNode( interface=fsl.FLIRT(apply_xfm=True, interp='nearestneighbour'), iterfield=['in_file', 'reference', 'in_matrix_file'], name='anatmasks_to_func4') # reg_anatmask_to_func2.inputs.apply_xfm = True # Create png images for quality check myqc = qc.vol2png("func2anat") # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds_nii') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # Define outputs of the workflow outputspec = pe.Node(utility.IdentityInterface(fields=[ 'func_sample2anat', 'example_func', 'func_to_anat_linear_xfm', 'anat_to_func_linear_xfm', 'csf_mask_in_funcspace', 'wm_mask_in_funcspace', 'gm_mask_in_funcspace', 'ventricle_mask_in_funcspace' ]), name='outputspec') analysisflow = pe.Workflow(name=wf_name) analysisflow.base_dir = '.' analysisflow.connect(inputspec, 'func', myonevol, 'inputspec.func') analysisflow.connect(myonevol, 'outputspec.func1vol', linear_reg, 'in_file') analysisflow.connect(inputspec, 'skull', linear_reg, 'reference') analysisflow.connect(linear_reg, 'out_matrix_file', bbreg_func_to_anat, 'in_matrix_file') analysisflow.connect(myonevol, 'outputspec.func1vol', bbreg_func_to_anat, 'in_file') analysisflow.connect(inputspec, 'anat_wm_segmentation', bbreg_arg_convert, 'bbreg_target') analysisflow.connect(bbreg_arg_convert, 'arg', bbreg_func_to_anat, 'args') analysisflow.connect(inputspec, 'skull', bbreg_func_to_anat, 'reference') analysisflow.connect(bbreg_func_to_anat, 'out_matrix_file', convertmatrix, 'in_file') analysisflow.connect(convertmatrix, 'out_file', reg_anatmask_to_func1, 'in_matrix_file') analysisflow.connect(myonevol, 'outputspec.func1vol', reg_anatmask_to_func1, 'reference') analysisflow.connect(csf_bb_mask, 'out_file', reg_anatmask_to_func1, 'in_file') analysisflow.connect(convertmatrix, 'out_file', reg_anatmask_to_func2, 'in_matrix_file') analysisflow.connect(myonevol, 'outputspec.func1vol', reg_anatmask_to_func2, 'reference') analysisflow.connect(wm_bb_mask, 'out_file', reg_anatmask_to_func2, 'in_file') analysisflow.connect(convertmatrix, 'out_file', reg_anatmask_to_func3, 'in_matrix_file') analysisflow.connect(myonevol, 'outputspec.func1vol', reg_anatmask_to_func3, 'reference') analysisflow.connect(gm_bb_mask, 'out_file', reg_anatmask_to_func3, 'in_file') analysisflow.connect(convertmatrix, 'out_file', reg_anatmask_to_func4, 'in_matrix_file') analysisflow.connect(myonevol, 'outputspec.func1vol', reg_anatmask_to_func4, 'reference') analysisflow.connect(vent_bb_mask, 'out_file', reg_anatmask_to_func4, 'in_file') analysisflow.connect(inputspec, 'anat_wm_segmentation', wm_bb_mask, 'in_file') analysisflow.connect(inputspec, 'anat_csf_segmentation', csf_bb_mask, 'in_file') analysisflow.connect(inputspec, 'anat_gm_segmentation', gm_bb_mask, 'in_file') analysisflow.connect(inputspec, 'anat_ventricle_segmentation', vent_bb_mask, 'in_file') analysisflow.connect(bbreg_func_to_anat, 'out_file', outputspec, 'func_sample2anat') analysisflow.connect(bbreg_func_to_anat, 'out_matrix_file', outputspec, 'func_to_anat_linear_xfm') analysisflow.connect(reg_anatmask_to_func1, 'out_file', outputspec, 'csf_mask_in_funcspace') analysisflow.connect(reg_anatmask_to_func2, 'out_file', outputspec, 'wm_mask_in_funcspace') analysisflow.connect(reg_anatmask_to_func3, 'out_file', outputspec, 'gm_mask_in_funcspace') analysisflow.connect(reg_anatmask_to_func4, 'out_file', outputspec, 'ventricle_mask_in_funcspace') analysisflow.connect(myonevol, 'outputspec.func1vol', outputspec, 'example_func') analysisflow.connect(convertmatrix, 'out_file', outputspec, 'anat_to_func_linear_xfm') analysisflow.connect(bbreg_func_to_anat, 'out_file', ds, "func2anat") analysisflow.connect(bbreg_func_to_anat, 'out_file', myqc, 'inputspec.bg_image') analysisflow.connect(wm_bb_mask, 'out_file', myqc, 'inputspec.overlay_image') return analysisflow
def anat2mni_fsl_workflow(SinkTag="anat_preproc", wf_name="anat2mni_fsl"): """ Modified version of CPAC.registration.registration: `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/registration/registration.html` Register skull and brain extracted image to MNI space and return the transformation martices. Workflow inputs: :param skull: The reoriented anatomical file. :param brain: The brain extracted anat. :param ref_skull: MNI152 skull file. :param ref_brain: MNI152 brain file. :param ref_mask: CSF mask of the MNI152 file. :param fnirt config: Parameters which specifies FNIRT options. :param SinkDir: :param SinkTag: The output directiry in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: anat2mni_workflow - workflow anat="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres.nii.gz", brain="/home/balint/Dokumentumok/phd/essen/PAINTER/probe/MS001/highres_brain.nii.gz", Balint Kincses [email protected] 2018 """ SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Define inputs of workflow inputspec = pe.Node(utility.IdentityInterface(fields=[ 'brain', 'skull', 'reference_brain', 'reference_skull', 'ref_mask', 'fnirt_config' ]), name='inputspec') inputspec.inputs.reference_brain = globals._FSLDIR_ + globals._brainref inputspec.inputs.reference_skull = globals._FSLDIR_ + globals._headref inputspec.inputs.ref_mask = globals._FSLDIR_ + globals._brainref_mask # inputspec.inputs.fnirt_config = "T1_2_MNI152_2mm" # Linear registration node linear_reg = pe.MapNode(interface=fsl.FLIRT(), iterfield=['in_file'], name='linear_reg_0') linear_reg.inputs.cost = 'corratio' # Non-linear registration node nonlinear_reg = pe.MapNode(interface=fsl.FNIRT(), iterfield=['in_file', 'affine_file'], name='nonlinear_reg_1') nonlinear_reg.inputs.fieldcoeff_file = True nonlinear_reg.inputs.jacobian_file = True # Applying warp field brain_warp = pe.MapNode(interface=fsl.ApplyWarp(), iterfield=['in_file', 'field_file'], name='brain_warp') # Calculate the invers of the linear transformation inv_flirt_xfm = pe.MapNode(interface=fsl.utils.ConvertXFM(), iterfield=['in_file'], name='inv_linear_reg0_xfm') inv_flirt_xfm.inputs.invert_xfm = True # Calculate inverse of the nonlinear warping field inv_fnirt_xfm = pe.MapNode(interface=fsl.utils.InvWarp(), iterfield=['warp', 'reference'], name="inv_nonlinear_xfm") # Create png images for quality check myqc = qc.vol2png("anat2mni", "FSL2", overlayiterated=False) myqc.inputs.inputspec.overlay_image = globals._FSLDIR_ + globals._brainref myqc.inputs.slicer.image_width = 500 myqc.inputs.slicer.threshold_edges = 0.1 # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] # Define outputs of the workflow outputspec = pe.Node(utility.IdentityInterface(fields=[ 'output_brain', 'linear_xfm', 'invlinear_xfm', 'nonlinear_xfm', 'invnonlinear_xfm', 'std_template' ]), name='outputspec') # Create workflow nad connect nodes analysisflow = pe.Workflow(name=wf_name) analysisflow.connect(inputspec, 'brain', linear_reg, 'in_file') analysisflow.connect(inputspec, 'reference_brain', linear_reg, 'reference') analysisflow.connect(inputspec, 'skull', nonlinear_reg, 'in_file') analysisflow.connect(inputspec, 'reference_skull', nonlinear_reg, 'ref_file') analysisflow.connect(inputspec, 'ref_mask', nonlinear_reg, 'refmask_file') # FNIRT parameters are specified by FSL config file # ${FSLDIR}/etc/flirtsch/TI_2_MNI152_2mm.cnf (or user-specified) analysisflow.connect(inputspec, 'fnirt_config', nonlinear_reg, 'config_file') analysisflow.connect(linear_reg, 'out_matrix_file', nonlinear_reg, 'affine_file') analysisflow.connect(nonlinear_reg, 'fieldcoeff_file', outputspec, 'nonlinear_xfm') analysisflow.connect(nonlinear_reg, 'field_file', outputspec, 'field_file') analysisflow.connect(inputspec, 'brain', brain_warp, 'in_file') analysisflow.connect(nonlinear_reg, 'fieldcoeff_file', brain_warp, 'field_file') analysisflow.connect(inputspec, 'reference_brain', brain_warp, 'ref_file') analysisflow.connect(brain_warp, 'out_file', outputspec, 'output_brain') analysisflow.connect(linear_reg, 'out_matrix_file', inv_flirt_xfm, 'in_file') analysisflow.connect(inv_flirt_xfm, 'out_file', outputspec, 'invlinear_xfm') analysisflow.connect(nonlinear_reg, 'fieldcoeff_file', inv_fnirt_xfm, 'warp') analysisflow.connect(inputspec, 'brain', inv_fnirt_xfm, 'reference') analysisflow.connect(inv_fnirt_xfm, 'inverse_warp', outputspec, 'invnonlinear_xfm') analysisflow.connect(linear_reg, 'out_matrix_file', outputspec, 'linear_xfm') analysisflow.connect(inputspec, 'reference_brain', outputspec, 'std_template') analysisflow.connect(brain_warp, 'out_file', ds, 'anat2mni_std') analysisflow.connect(nonlinear_reg, 'fieldcoeff_file', ds, 'anat2mni_warpfield') analysisflow.connect(brain_warp, 'out_file', myqc, 'inputspec.bg_image') return analysisflow
def bet_workflow(Robust=True, fmri=False, SinkTag="anat_preproc", wf_name="brain_extraction"): """ Modified version of CPAC.anat_preproc.anat_preproc: `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/anat_preproc/anat_preproc.html` Creates a brain extracted image and its mask from a T1w anatomical image. Workflow inputs: :param anat: The reoriented anatomical file. :param SinkDir: :param SinkTag: The output directiry in which the returned images (see workflow outputs) could be found. Workflow outputs: :return: bet_workflow - workflow Balint Kincses [email protected] 2018 """ import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.interfaces.io as io import PUMI.utils.QC as qc import PUMI.utils.globals as globals import PUMI.func_preproc.Onevol as onevol SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) #Basic interface class generates identity mappings inputspec = pe.Node( utility.IdentityInterface(fields=[ 'in_file', 'opt_R', 'fract_int_thr', # optional 'vertical_gradient' ]), # optional name='inputspec') inputspec.inputs.opt_R = Robust if fmri: inputspec.inputs.fract_int_thr = globals._fsl_bet_fract_int_thr_func_ else: inputspec.inputs.fract_int_thr = globals._fsl_bet_fract_int_thr_anat_ inputspec.inputs.vertical_gradient = globals._fsl_bet_vertical_gradient_ #Wraps command **bet** bet = pe.MapNode(interface=fsl.BET(), iterfield=['in_file'], name='bet') bet.inputs.mask = True # bet.inputs.robust=Robust if fmri: bet.inputs.functional = True myonevol = onevol.onevol_workflow(wf_name="onevol") applymask = pe.MapNode(fsl.ApplyMask(), iterfield=['in_file', 'mask_file'], name="apply_mask") myqc = qc.vol2png(wf_name, overlay=True) #Basic interface class generates identity mappings outputspec = pe.Node( utility.IdentityInterface(fields=['brain', 'brain_mask']), name='outputspec') # Save outputs which are important ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir ds.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] #Create a workflow to connect all those nodes analysisflow = nipype.Workflow( wf_name) # The name here determine the folder of the workspace analysisflow.base_dir = '.' analysisflow.connect(inputspec, 'in_file', bet, 'in_file') analysisflow.connect(inputspec, 'opt_R', bet, 'robust') analysisflow.connect(inputspec, 'fract_int_thr', bet, 'frac') analysisflow.connect(inputspec, 'vertical_gradient', bet, 'vertical_gradient') analysisflow.connect(bet, 'mask_file', outputspec, 'brain_mask') if fmri: analysisflow.connect(bet, 'mask_file', myonevol, 'inputspec.func') analysisflow.connect(myonevol, 'outputspec.func1vol', applymask, 'mask_file') analysisflow.connect(inputspec, 'in_file', applymask, 'in_file') analysisflow.connect(applymask, 'out_file', outputspec, 'brain') else: analysisflow.connect(bet, 'out_file', outputspec, 'brain') analysisflow.connect(bet, 'out_file', ds, 'bet_brain') analysisflow.connect(bet, 'mask_file', ds, 'brain_mask') analysisflow.connect(inputspec, 'in_file', myqc, 'inputspec.bg_image') analysisflow.connect(bet, 'out_file', myqc, 'inputspec.overlay_image') return analysisflow
def mc_workflow_fsl(reference_vol="mid", FD_mode="Power", SinkTag="func_preproc", wf_name="motion_correction_fsl"): """ Modified version of CPAC.func_preproc.func_preproc and CPAC.generate_motion_statistics.generate_motion_statistics: `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/func_preproc/func_preproc.html` `source: https://fcp-indi.github.io/docs/developer/_modules/CPAC/generate_motion_statistics/generate_motion_statistics.html` Use FSL MCFLIRT to do the motion correction of the 4D functional data and use the 6df rigid body motion parameters to calculate friston24 parameters for later nuissance regression step. Workflow inputs: :param func: The reoriented functional file. :param reference_vol: Either "first", "mid", "last", "mean", or the index of the volume which the rigid body registration (motion correction) will use as reference. default: "mid" :param FD_mode Eiher "Power" or "Jenkinson" :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow.. Workflow outputs: :return: mc_workflow - workflow Balint Kincses [email protected] 2018 """ # TODO_ready nipype has the ability to calculate FD: the function from CPAC calculates it correctly # import relevant packages import sys import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import nipype.interfaces.fsl as fsl import nipype.algorithms.confounds as conf import PUMI.func_preproc.info.info_get as info_get import nipype.interfaces.io as io import PUMI.utils.utils_math as utils_math import PUMI.utils.utils_convert as utils_convert import PUMI.utils.globals as globals import PUMI.utils.QC as qc SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) QCDir = os.path.abspath(globals._SinkDir_ + "/" + globals._QCDir_) if not os.path.exists(QCDir): os.makedirs(QCDir) # Basic interface class generates identity mappings inputspec = pe.Node(utility.IdentityInterface( fields=['func', 'ref_vol', 'save_plots', 'stats_imgs']), name='inputspec') inputspec.inputs.save_plots = True inputspec.inputs.stats_imgs = True inputspec.inputs.ref_vol = reference_vol # todo_ready: make parametrizable: the reference_vol variable is an argumentum of the mc_workflow # extract reference volume refvol = pe.MapNode(utility.Function(input_names=['refvol', 'func'], output_names=['refvol'], function=getRefVol), iterfield=['func'], name='getRefVol') # Wraps command **mcflirt** mcflirt = pe.MapNode( interface=fsl.MCFLIRT( interpolation="spline", stats_imgs=False), # stages=4), #stages 4: more accurate but slow iterfield=['in_file', 'ref_file'], # , 'ref_vol'], # make parametrizable name='mcflirt') if (reference_vol == "mean"): mcflirt = pe.MapNode( interface=fsl.MCFLIRT(interpolation="spline", stats_imgs=False), # stages=4), #stages 4: more accurate but slow iterfield=['in_file'], # , 'ref_vol'], # make parametrizable name='mcflirt') mcflirt.inputs.mean_vol = True else: mcflirt = pe.MapNode( interface=fsl.MCFLIRT(interpolation="spline", stats_imgs=False), # stages=4), #stages 4: more accurate but slow iterfield=['in_file', 'ref_file'], # , 'ref_vol'], # make parametrizable name='mcflirt') mcflirt.inputs.dof = 6 mcflirt.inputs.save_mats = True mcflirt.inputs.save_plots = True mcflirt.inputs.save_rms = True mcflirt.inputs.stats_imgs = False myqc = qc.timecourse2png("timeseries", tag="010_motioncorr") # Calculate Friston24 parameters calc_friston = pe.MapNode(utility.Function( input_names=['in_file'], output_names=['out_file'], function=calc_friston_twenty_four), iterfield=['in_file'], name='calc_friston') # Calculate FD based on Power's method if FD_mode == "Power": calculate_FD = pe.MapNode(conf.FramewiseDisplacement( parameter_source='FSL', save_plot=True), iterfield=['in_file'], name='calculate_FD_Power') elif FD_mode == "Jenkinson": calculate_FD = pe.MapNode(utility.Function(input_names=['in_file'], output_names=['out_file'], function=calculate_FD_J), iterfield=['in_file'], name='calculate_FD_Jenkinson') # compute mean and max FD meanFD = pe.MapNode(interface=utils_math.Txt2meanTxt, iterfield=['in_file'], name='meanFD') meanFD.inputs.axis = 0 # global mean meanFD.inputs.header = True # global mean maxFD = pe.MapNode(interface=utils_math.Txt2maxTxt, iterfield=['in_file'], name='maxFD') maxFD.inputs.axis = 0 # global mean maxFD.inputs.header = True pop_FD = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_FD') pop_FDmax = pe.Node(interface=utils_convert.List2TxtFileOpen, name='pop_FDmax') # save data out with Datasink ds_fd = pe.Node(interface=io.DataSink(), name='ds_pop_fd') ds_fd.inputs.regexp_substitutions = [("(\/)[^\/]*$", "FD.txt")] ds_fd.inputs.base_directory = SinkDir # save data out with Datasink ds_fd_max = pe.Node(interface=io.DataSink(), name='ds_pop_fd_max') ds_fd_max.inputs.regexp_substitutions = [("(\/)[^\/]*$", "FD_max.txt")] ds_fd_max.inputs.base_directory = SinkDir plot_motion_rot = pe.MapNode( interface=fsl.PlotMotionParams(in_source='fsl'), name='plot_motion_rot', iterfield=['in_file']) plot_motion_rot.inputs.plot_type = 'rotations' plot_motion_tra = pe.MapNode( interface=fsl.PlotMotionParams(in_source='fsl'), name='plot_motion_trans', iterfield=['in_file']) plot_motion_tra.inputs.plot_type = 'translations' # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=[ 'func_out_file', 'first24_file', 'mat_file', 'mc_par_file', 'FD_file' ]), name='outputspec') # save data out with Datasink ds_nii = pe.Node(interface=io.DataSink(), name='ds_nii') ds_nii.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".nii.gz")] ds_nii.inputs.base_directory = SinkDir # save data out with Datasink ds_text = pe.Node(interface=io.DataSink(), name='ds_txt') ds_text.inputs.regexp_substitutions = [("(\/)[^\/]*$", ".txt")] ds_text.inputs.base_directory = SinkDir # Save outputs which are important ds_qc_fd = pe.Node(interface=io.DataSink(), name='ds_qc_fd') ds_qc_fd.inputs.base_directory = QCDir ds_qc_fd.inputs.regexp_substitutions = [("(\/)[^\/]*$", "_FD.pdf")] # Save outputs which are important ds_qc_rot = pe.Node(interface=io.DataSink(), name='ds_qc_rot') ds_qc_rot.inputs.base_directory = QCDir ds_qc_rot.inputs.regexp_substitutions = [("(\/)[^\/]*$", "_rot.png")] # Save outputs which are important ds_qc_tra = pe.Node(interface=io.DataSink(), name='ds_qc_tra') ds_qc_tra.inputs.base_directory = QCDir ds_qc_tra.inputs.regexp_substitutions = [("(\/)[^\/]*$", "_trans.png")] #TODO_ready set the proper images which has to be saved in a the datasink specified directory # Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'func', mcflirt, 'in_file') analysisflow.connect(inputspec, 'func', refvol, 'func') analysisflow.connect(inputspec, 'ref_vol', refvol, 'refvol') if (reference_vol != "mean"): analysisflow.connect(refvol, 'refvol', mcflirt, 'ref_file') analysisflow.connect(mcflirt, 'par_file', calc_friston, 'in_file') analysisflow.connect(mcflirt, 'par_file', calculate_FD, 'in_file') analysisflow.connect(mcflirt, 'out_file', outputspec, 'func_out_file') analysisflow.connect(mcflirt, 'mat_file', outputspec, 'mat_file') analysisflow.connect(mcflirt, 'par_file', outputspec, 'mc_par_file') analysisflow.connect(mcflirt, 'out_file', ds_nii, 'mc_func') analysisflow.connect(mcflirt, 'par_file', ds_text, 'mc_par') #analysisflow.connect(mcflirt, 'std_img', ds, 'mc.@std_img') analysisflow.connect(mcflirt, 'rms_files', ds_text, 'mc_rms') #analysisflow.connect(mcflirt, 'variance_img', ds, 'mc.@variance_img') analysisflow.connect(calc_friston, 'out_file', outputspec, 'first24_file') analysisflow.connect(calc_friston, 'out_file', ds_text, 'mc_first24') analysisflow.connect(calculate_FD, 'out_file', outputspec, 'FD_file') analysisflow.connect(mcflirt, 'par_file', plot_motion_rot, 'in_file') analysisflow.connect(mcflirt, 'par_file', plot_motion_tra, 'in_file') analysisflow.connect(plot_motion_rot, 'out_file', ds_qc_rot, 'motion_correction') analysisflow.connect(plot_motion_tra, 'out_file', ds_qc_tra, 'motion_correction') analysisflow.connect(mcflirt, 'out_file', myqc, 'inputspec.func') # pop-level mean FD analysisflow.connect(calculate_FD, 'out_file', meanFD, 'in_file') analysisflow.connect(calculate_FD, 'out_file', ds_text, 'mc_fd') analysisflow.connect(calculate_FD, 'out_figure', ds_qc_fd, 'FD') analysisflow.connect(meanFD, 'mean_file', pop_FD, 'in_list') analysisflow.connect(pop_FD, 'txt_file', ds_fd, 'pop') analysisflow.connect(calculate_FD, 'out_file', maxFD, 'in_file') analysisflow.connect(maxFD, 'max_file', pop_FDmax, 'in_list') analysisflow.connect(pop_FDmax, 'txt_file', ds_fd_max, 'pop') return analysisflow