def rsfMRI_filtering_pipeline(self, **name_maps): pipeline = self.new_pipeline( name='rsfMRI_filtering', desc=("Spatial and temporal rsfMRI filtering"), citations=[fsl_cite], name_maps=name_maps) afni_mc = pipeline.add( 'AFNI_MC', Volreg( zpad=1, out_file='rsfmri_mc.nii.gz', oned_file='prefiltered_func_data_mcf.par'), inputs={ 'in_file': ('series_preproc', nifti_gz_format)}, outputs={ 'mc_par': ('oned_file', par_format)}, wall_time=5, requirements=[afni_req.v('16.2.10')]) filt = pipeline.add( 'Tproject', Tproject( stopband=(0, 0.01), polort=3, blur=3, out_file='filtered_func_data.nii.gz'), inputs={ 'delta_t': ('tr', float), 'mask': ('brain_mask', nifti_gz_format), 'in_file': (afni_mc, 'out_file')}, wall_time=5, requirements=[afni_req.v('16.2.10')]) meanfunc = pipeline.add( 'meanfunc', ImageMaths( op_string='-Tmean', suffix='_mean', output_type='NIFTI_GZ'), wall_time=5, inputs={ 'in_file': (afni_mc, 'out_file')}, requirements=[fsl_req.v('5.0.10')]) pipeline.add( 'add_mean', ImageMaths( op_string='-add', output_type='NIFTI_GZ'), inputs={ 'in_file': (filt, 'out_file'), 'in_file2': (meanfunc, 'out_file')}, outputs={ 'filtered_data': ('out_file', nifti_gz_format)}, wall_time=5, requirements=[fsl_req.v('5.0.10')]) return pipeline
def rsfMRI_filtering_pipeline(self, **kwargs): pipeline = self.create_pipeline( name='rsfMRI_filtering', inputs=[ DatasetSpec('preproc', nifti_gz_format), DatasetSpec('brain_mask', nifti_gz_format), DatasetSpec('coreg_ref_brain', nifti_gz_format), FieldSpec('tr', float) ], outputs=[ DatasetSpec('filtered_data', nifti_gz_format), DatasetSpec('mc_par', par_format) ], desc=("Spatial and temporal rsfMRI filtering"), version=1, citations=[fsl_cite], **kwargs) afni_mc = pipeline.create_node(Volreg(), name='AFNI_MC', wall_time=5, requirements=[afni_req]) afni_mc.inputs.zpad = 1 afni_mc.inputs.out_file = 'rsfmri_mc.nii.gz' afni_mc.inputs.oned_file = 'prefiltered_func_data_mcf.par' pipeline.connect_input('preproc', afni_mc, 'in_file') filt = pipeline.create_node(Tproject(), name='Tproject', wall_time=5, requirements=[afni_req]) filt.inputs.stopband = (0, 0.01) filt.inputs.polort = 3 filt.inputs.blur = 3 filt.inputs.out_file = 'filtered_func_data.nii.gz' pipeline.connect_input('tr', filt, 'delta_t') pipeline.connect(afni_mc, 'out_file', filt, 'in_file') pipeline.connect_input('brain_mask', filt, 'mask') meanfunc = pipeline.create_node(ImageMaths(op_string='-Tmean', suffix='_mean'), name='meanfunc', wall_time=5, requirements=[fsl5_req]) pipeline.connect(afni_mc, 'out_file', meanfunc, 'in_file') add_mean = pipeline.create_node(ImageMaths(op_string='-add'), name='add_mean', wall_time=5, requirements=[fsl5_req]) pipeline.connect(filt, 'out_file', add_mean, 'in_file') pipeline.connect(meanfunc, 'out_file', add_mean, 'in_file2') pipeline.connect_output('filtered_data', add_mean, 'out_file') pipeline.connect_output('mc_par', afni_mc, 'oned_file') return pipeline
def test_ImageMaths_outputs(): output_map = dict(out_file=dict(), ) outputs = ImageMaths.output_spec() for key, metadata in output_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(outputs.traits()[key], metakey), value
def test_ImageMaths_inputs(): input_map = dict( args=dict(argstr='%s', ), environ=dict( nohash=True, usedefault=True, ), ignore_exception=dict( nohash=True, usedefault=True, ), in_file=dict( argstr='%s', mandatory=True, position=1, ), in_file2=dict( argstr='%s', position=3, ), op_string=dict( argstr='%s', position=2, ), out_data_type=dict( argstr='-odt %s', position=5, ), out_file=dict( argstr='%s', genfile=True, hash_files=False, position=4, ), output_type=dict(), suffix=dict(), terminal_output=dict( mandatory=True, nohash=True, ), ) inputs = ImageMaths.input_spec() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(inputs.traits()[key], metakey), value
def test_ImageMaths_inputs(): input_map = dict(args=dict(argstr='%s', ), environ=dict(nohash=True, usedefault=True, ), ignore_exception=dict(nohash=True, usedefault=True, ), in_file=dict(argstr='%s', mandatory=True, position=1, ), in_file2=dict(argstr='%s', position=3, ), op_string=dict(argstr='%s', position=2, ), out_data_type=dict(argstr='-odt %s', position=5, ), out_file=dict(argstr='%s', genfile=True, hash_files=False, position=4, ), output_type=dict(), suffix=dict(), terminal_output=dict(mandatory=True, nohash=True, ), ) inputs = ImageMaths.input_spec() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(inputs.traits()[key], metakey), value
def firstlevel_wf(subject_id, sink_directory, name='wmaze_frstlvl_wf'): frstlvl_wf = Workflow(name='frstlvl_wf') info = dict( task_mri_files=[['subject_id', 'wmaze']], #dictionary used in datasource motion_noise_files=[['subject_id']]) #function node to call subjectinfo function with name, onset, duration, and amplitude info subject_info = Node(Function(input_names=['subject_id'], output_names=['output'], function=subjectinfo), name='subject_info') subject_info.inputs.ignore_exception = False subject_info.inputs.subject_id = subject_id #function node to define contrasts getcontrasts = Node(Function(input_names=['subject_id', 'info'], output_names=['contrasts'], function=get_contrasts), name='getcontrasts') getcontrasts.inputs.ignore_exception = False getcontrasts.inputs.subject_id = subject_id frstlvl_wf.connect(subject_info, 'output', getcontrasts, 'info') #function node to substitute names of folders and files created during pipeline getsubs = Node( Function( input_names=['cons'], output_names=['subs'], # Calls the function 'get_subs' function=get_subs), name='getsubs') getsubs.inputs.ignore_exception = False getsubs.inputs.subject_id = subject_id frstlvl_wf.connect(subject_info, 'output', getsubs, 'info') frstlvl_wf.connect(getcontrasts, 'contrasts', getsubs, 'cons') #datasource node to get task_mri and motion-noise files datasource = Node(DataGrabber(infields=['subject_id'], outfields=info.keys()), name='datasource') datasource.inputs.template = '*' datasource.inputs.subject_id = subject_id datasource.inputs.base_directory = os.path.abspath( '/home/data/madlab/data/mri/wmaze/preproc/') datasource.inputs.field_template = dict( task_mri_files= '%s/func/smoothed_fullspectrum/_maskfunc2*/*%s*.nii.gz', #functional files motion_noise_files='%s/noise/filter_regressor??.txt' ) #filter regressor noise files datasource.inputs.template_args = info datasource.inputs.sort_filelist = True datasource.inputs.ignore_exception = False datasource.inputs.raise_on_empty = True #function node to remove last three volumes from functional data fslroi_epi = MapNode( ExtractROI(t_min=0, t_size=197), #start from first volume and end on -3 iterfield=['in_file'], name='fslroi_epi') fslroi_epi.output_type = 'NIFTI_GZ' fslroi_epi.terminal_output = 'stream' frstlvl_wf.connect(datasource, 'task_mri_files', fslroi_epi, 'in_file') #function node to modify the motion and noise files to be single regressors motionnoise = Node(Function(input_names=['subjinfo', 'files'], output_names=['subjinfo'], function=motion_noise), name='motionnoise') motionnoise.inputs.ignore_exception = False frstlvl_wf.connect(subject_info, 'output', motionnoise, 'subjinfo') frstlvl_wf.connect(datasource, 'motion_noise_files', motionnoise, 'files') #node to create model specifications compatible with spm/fsl designers (requires subjectinfo to be received in the form of a Bunch) specify_model = Node(SpecifyModel(), name='specify_model') specify_model.inputs.high_pass_filter_cutoff = -1.0 #high-pass filter cutoff in seconds specify_model.inputs.ignore_exception = False specify_model.inputs.input_units = 'secs' #input units in either 'secs' or 'scans' specify_model.inputs.time_repetition = 2.0 #TR frstlvl_wf.connect( fslroi_epi, 'roi_file', specify_model, 'functional_runs') #editted data files for model -- list of 4D files #list of event description files in 3 column format corresponding to onsets, durations, and amplitudes frstlvl_wf.connect(motionnoise, 'subjinfo', specify_model, 'subject_info') #node for basic interface class generating identity mappings modelfit_inputspec = Node(IdentityInterface(fields=[ 'session_info', 'interscan_interval', 'contrasts', 'film_threshold', 'functional_data', 'bases', 'model_serial_correlations' ], mandatory_inputs=True), name='modelfit_inputspec') modelfit_inputspec.inputs.bases = {'dgamma': {'derivs': False}} modelfit_inputspec.inputs.film_threshold = 0.0 modelfit_inputspec.inputs.interscan_interval = 2.0 modelfit_inputspec.inputs.model_serial_correlations = True frstlvl_wf.connect(fslroi_epi, 'roi_file', modelfit_inputspec, 'functional_data') frstlvl_wf.connect(getcontrasts, 'contrasts', modelfit_inputspec, 'contrasts') frstlvl_wf.connect(specify_model, 'session_info', modelfit_inputspec, 'session_info') #node for first level SPM design matrix to demonstrate contrasts and motion/noise regressors level1_design = MapNode(Level1Design(), iterfield=['contrasts', 'session_info'], name='level1_design') level1_design.inputs.ignore_exception = False frstlvl_wf.connect(modelfit_inputspec, 'interscan_interval', level1_design, 'interscan_interval') frstlvl_wf.connect(modelfit_inputspec, 'session_info', level1_design, 'session_info') frstlvl_wf.connect(modelfit_inputspec, 'contrasts', level1_design, 'contrasts') frstlvl_wf.connect(modelfit_inputspec, 'bases', level1_design, 'bases') frstlvl_wf.connect(modelfit_inputspec, 'model_serial_correlations', level1_design, 'model_serial_correlations') #MapNode to generate a design.mat file for each run generate_model = MapNode(FEATModel(), iterfield=['fsf_file', 'ev_files'], name='generate_model') generate_model.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} generate_model.inputs.ignore_exception = False generate_model.inputs.output_type = 'NIFTI_GZ' generate_model.inputs.terminal_output = 'stream' frstlvl_wf.connect(level1_design, 'fsf_files', generate_model, 'fsf_file') frstlvl_wf.connect(level1_design, 'ev_files', generate_model, 'ev_files') #MapNode to estimate the model using FILMGLS -- fits the design matrix to the voxel timeseries estimate_model = MapNode(FILMGLS(), iterfield=['design_file', 'in_file', 'tcon_file'], name='estimate_model') estimate_model.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} estimate_model.inputs.ignore_exception = False estimate_model.inputs.mask_size = 5 #Susan-smooth mask size estimate_model.inputs.output_type = 'NIFTI_GZ' estimate_model.inputs.results_dir = 'results' estimate_model.inputs.smooth_autocorr = True #smooth auto-correlation estimates estimate_model.inputs.terminal_output = 'stream' frstlvl_wf.connect(modelfit_inputspec, 'film_threshold', estimate_model, 'threshold') frstlvl_wf.connect(modelfit_inputspec, 'functional_data', estimate_model, 'in_file') frstlvl_wf.connect( generate_model, 'design_file', estimate_model, 'design_file') #mat file containing ascii matrix for design frstlvl_wf.connect(generate_model, 'con_file', estimate_model, 'tcon_file') #contrast file containing contrast vectors #merge node to merge the contrasts - necessary for fsl 5.0.7 and greater merge_contrasts = MapNode(Merge(2), iterfield=['in1'], name='merge_contrasts') frstlvl_wf.connect(estimate_model, 'zstats', merge_contrasts, 'in1') #MapNode to transform the z2pval z2pval = MapNode(ImageMaths(), iterfield=['in_file'], name='z2pval') z2pval.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} z2pval.inputs.ignore_exception = False z2pval.inputs.op_string = '-ztop' #defines the operation used z2pval.inputs.output_type = 'NIFTI_GZ' z2pval.inputs.suffix = '_pval' z2pval.inputs.terminal_output = 'stream' frstlvl_wf.connect(merge_contrasts, ('out', pop_lambda), z2pval, 'in_file') #outputspec node using IdentityInterface() to receive information from estimate_model, merge_contrasts, z2pval, generate_model, and estimate_model modelfit_outputspec = Node(IdentityInterface(fields=[ 'copes', 'varcopes', 'dof_file', 'pfiles', 'parameter_estimates', 'zstats', 'design_image', 'design_file', 'design_cov', 'sigmasquareds' ], mandatory_inputs=True), name='modelfit_outputspec') frstlvl_wf.connect(estimate_model, 'copes', modelfit_outputspec, 'copes') #lvl1 cope files frstlvl_wf.connect(estimate_model, 'varcopes', modelfit_outputspec, 'varcopes') #lvl1 varcope files frstlvl_wf.connect(merge_contrasts, 'out', modelfit_outputspec, 'zstats') #zstats across runs frstlvl_wf.connect(z2pval, 'out_file', modelfit_outputspec, 'pfiles') frstlvl_wf.connect( generate_model, 'design_image', modelfit_outputspec, 'design_image') #graphical representation of design matrix frstlvl_wf.connect( generate_model, 'design_file', modelfit_outputspec, 'design_file') #mat file containing ascii matrix for design frstlvl_wf.connect( generate_model, 'design_cov', modelfit_outputspec, 'design_cov') #graphical representation of design covariance frstlvl_wf.connect(estimate_model, 'param_estimates', modelfit_outputspec, 'parameter_estimates' ) #parameter estimates for columns of design matrix frstlvl_wf.connect(estimate_model, 'dof_file', modelfit_outputspec, 'dof_file') #degrees of freedom frstlvl_wf.connect(estimate_model, 'sigmasquareds', modelfit_outputspec, 'sigmasquareds') #summary of residuals #datasink node to save output from multiple points in the pipeline sinkd = MapNode(DataSink(), iterfield=[ 'substitutions', 'modelfit.contrasts.@copes', 'modelfit.contrasts.@varcopes', 'modelfit.estimates', 'modelfit.contrasts.@zstats' ], name='sinkd') sinkd.inputs.base_directory = sink_directory sinkd.inputs.container = subject_id frstlvl_wf.connect(getsubs, 'subs', sinkd, 'substitutions') frstlvl_wf.connect(modelfit_outputspec, 'parameter_estimates', sinkd, 'modelfit.estimates') frstlvl_wf.connect(modelfit_outputspec, 'sigmasquareds', sinkd, 'modelfit.estimates.@sigsq') frstlvl_wf.connect(modelfit_outputspec, 'dof_file', sinkd, 'modelfit.dofs') frstlvl_wf.connect(modelfit_outputspec, 'copes', sinkd, 'modelfit.contrasts.@copes') frstlvl_wf.connect(modelfit_outputspec, 'varcopes', sinkd, 'modelfit.contrasts.@varcopes') frstlvl_wf.connect(modelfit_outputspec, 'zstats', sinkd, 'modelfit.contrasts.@zstats') frstlvl_wf.connect(modelfit_outputspec, 'design_image', sinkd, 'modelfit.design') frstlvl_wf.connect(modelfit_outputspec, 'design_cov', sinkd, 'modelfit.design.@cov') frstlvl_wf.connect(modelfit_outputspec, 'design_file', sinkd, 'modelfit.design.@matrix') frstlvl_wf.connect(modelfit_outputspec, 'pfiles', sinkd, 'modelfit.contrasts.@pstats') return frstlvl_wf
def Lesion_extractor( name='Lesion_Extractor', wf_name='Test', base_dir='/homes_unix/alaurent/', input_dir=None, subjects=None, main=None, acc=None, atlas='/homes_unix/alaurent/cbstools-public-master/atlases/brain-segmentation-prior3.0/brain-atlas-quant-3.0.8.txt' ): wf = Workflow(wf_name) wf.base_dir = base_dir #file = open(subjects,"r") #subjects = file.read().split("\n") #file.close() # Subject List subjectList = Node(IdentityInterface(fields=['subject_id'], mandatory_inputs=True), name="subList") subjectList.iterables = ('subject_id', [ sub for sub in subjects if sub != '' and sub != '\n' ]) # T1w and FLAIR scanList = Node(DataGrabber(infields=['subject_id'], outfields=['T1', 'FLAIR']), name="scanList") scanList.inputs.base_directory = input_dir scanList.inputs.ignore_exception = False scanList.inputs.raise_on_empty = True scanList.inputs.sort_filelist = True #scanList.inputs.template = '%s/%s.nii' #scanList.inputs.template_args = {'T1': [['subject_id','T1*']], # 'FLAIR': [['subject_id','FLAIR*']]} scanList.inputs.template = '%s/anat/%s' scanList.inputs.template_args = { 'T1': [['subject_id', '*_T1w.nii.gz']], 'FLAIR': [['subject_id', '*_FLAIR.nii.gz']] } wf.connect(subjectList, "subject_id", scanList, "subject_id") # # T1w and FLAIR # dg = Node(DataGrabber(outfields=['T1', 'FLAIR']), name="T1wFLAIR") # dg.inputs.base_directory = "/homes_unix/alaurent/LesionPipeline" # dg.inputs.template = "%s/NIFTI/*.nii.gz" # dg.inputs.template_args['T1']=[['7']] # dg.inputs.template_args['FLAIR']=[['9']] # dg.inputs.sort_filelist=True # Reorient Volume T1Conv = Node(Reorient2Std(), name="ReorientVolume") T1Conv.inputs.ignore_exception = False T1Conv.inputs.terminal_output = 'none' T1Conv.inputs.out_file = "T1_reoriented.nii.gz" wf.connect(scanList, "T1", T1Conv, "in_file") # Reorient Volume (2) T2flairConv = Node(Reorient2Std(), name="ReorientVolume2") T2flairConv.inputs.ignore_exception = False T2flairConv.inputs.terminal_output = 'none' T2flairConv.inputs.out_file = "FLAIR_reoriented.nii.gz" wf.connect(scanList, "FLAIR", T2flairConv, "in_file") # N3 Correction T1NUC = Node(N4BiasFieldCorrection(), name="N3Correction") T1NUC.inputs.dimension = 3 T1NUC.inputs.environ = {'NSLOTS': '1'} T1NUC.inputs.ignore_exception = False T1NUC.inputs.num_threads = 1 T1NUC.inputs.save_bias = False T1NUC.inputs.terminal_output = 'none' wf.connect(T1Conv, "out_file", T1NUC, "input_image") # N3 Correction (2) T2flairNUC = Node(N4BiasFieldCorrection(), name="N3Correction2") T2flairNUC.inputs.dimension = 3 T2flairNUC.inputs.environ = {'NSLOTS': '1'} T2flairNUC.inputs.ignore_exception = False T2flairNUC.inputs.num_threads = 1 T2flairNUC.inputs.save_bias = False T2flairNUC.inputs.terminal_output = 'none' wf.connect(T2flairConv, "out_file", T2flairNUC, "input_image") ''' ##################### ### PRE-NORMALIZE ### ##################### To make sure there's no outlier values (negative, or really high) to offset the initialization steps ''' # Intensity Range Normalization getMaxT1NUC = Node(ImageStats(op_string='-r'), name="getMaxT1NUC") wf.connect(T1NUC, 'output_image', getMaxT1NUC, 'in_file') T1NUCirn = Node(AbcImageMaths(), name="IntensityNormalization") T1NUCirn.inputs.op_string = "-div" T1NUCirn.inputs.out_file = "normT1.nii.gz" wf.connect(T1NUC, 'output_image', T1NUCirn, 'in_file') wf.connect(getMaxT1NUC, ('out_stat', getElementFromList, 1), T1NUCirn, "op_value") # Intensity Range Normalization (2) getMaxT2NUC = Node(ImageStats(op_string='-r'), name="getMaxT2") wf.connect(T2flairNUC, 'output_image', getMaxT2NUC, 'in_file') T2NUCirn = Node(AbcImageMaths(), name="IntensityNormalization2") T2NUCirn.inputs.op_string = "-div" T2NUCirn.inputs.out_file = "normT2.nii.gz" wf.connect(T2flairNUC, 'output_image', T2NUCirn, 'in_file') wf.connect(getMaxT2NUC, ('out_stat', getElementFromList, 1), T2NUCirn, "op_value") ''' ######################## #### COREGISTRATION #### ######################## ''' # Optimized Automated Registration T2flairCoreg = Node(FLIRT(), name="OptimizedAutomatedRegistration") T2flairCoreg.inputs.output_type = 'NIFTI_GZ' wf.connect(T2NUCirn, "out_file", T2flairCoreg, "in_file") wf.connect(T1NUCirn, "out_file", T2flairCoreg, "reference") ''' ######################### #### SKULL-STRIPPING #### ######################### ''' # SPECTRE T1ss = Node(BET(), name="SPECTRE") T1ss.inputs.frac = 0.45 #0.4 T1ss.inputs.mask = True T1ss.inputs.outline = True T1ss.inputs.robust = True wf.connect(T1NUCirn, "out_file", T1ss, "in_file") # Image Calculator T2ss = Node(ApplyMask(), name="ImageCalculator") wf.connect(T1ss, "mask_file", T2ss, "mask_file") wf.connect(T2flairCoreg, "out_file", T2ss, "in_file") ''' #################################### #### 2nd LAYER OF N3 CORRECTION #### #################################### This time without the skull: there were some significant amounts of inhomogeneities leftover. ''' # N3 Correction (3) T1ssNUC = Node(N4BiasFieldCorrection(), name="N3Correction3") T1ssNUC.inputs.dimension = 3 T1ssNUC.inputs.environ = {'NSLOTS': '1'} T1ssNUC.inputs.ignore_exception = False T1ssNUC.inputs.num_threads = 1 T1ssNUC.inputs.save_bias = False T1ssNUC.inputs.terminal_output = 'none' wf.connect(T1ss, "out_file", T1ssNUC, "input_image") # N3 Correction (4) T2ssNUC = Node(N4BiasFieldCorrection(), name="N3Correction4") T2ssNUC.inputs.dimension = 3 T2ssNUC.inputs.environ = {'NSLOTS': '1'} T2ssNUC.inputs.ignore_exception = False T2ssNUC.inputs.num_threads = 1 T2ssNUC.inputs.save_bias = False T2ssNUC.inputs.terminal_output = 'none' wf.connect(T2ss, "out_file", T2ssNUC, "input_image") ''' #################################### #### NORMALIZE FOR MGDM #### #################################### This normalization is a bit aggressive: only useful to have a cropped dynamic range into MGDM, but possibly harmful to further processing, so the unprocessed images are passed to the subsequent steps. ''' # Intensity Range Normalization getMaxT1ssNUC = Node(ImageStats(op_string='-r'), name="getMaxT1ssNUC") wf.connect(T1ssNUC, 'output_image', getMaxT1ssNUC, 'in_file') T1ssNUCirn = Node(AbcImageMaths(), name="IntensityNormalization3") T1ssNUCirn.inputs.op_string = "-div" T1ssNUCirn.inputs.out_file = "normT1ss.nii.gz" wf.connect(T1ssNUC, 'output_image', T1ssNUCirn, 'in_file') wf.connect(getMaxT1ssNUC, ('out_stat', getElementFromList, 1), T1ssNUCirn, "op_value") # Intensity Range Normalization (2) getMaxT2ssNUC = Node(ImageStats(op_string='-r'), name="getMaxT2ssNUC") wf.connect(T2ssNUC, 'output_image', getMaxT2ssNUC, 'in_file') T2ssNUCirn = Node(AbcImageMaths(), name="IntensityNormalization4") T2ssNUCirn.inputs.op_string = "-div" T2ssNUCirn.inputs.out_file = "normT2ss.nii.gz" wf.connect(T2ssNUC, 'output_image', T2ssNUCirn, 'in_file') wf.connect(getMaxT2ssNUC, ('out_stat', getElementFromList, 1), T2ssNUCirn, "op_value") ''' #################################### #### ESTIMATE CSF PV #### #################################### Here we try to get a better handle on CSF voxels to help the segmentation step ''' # Recursive Ridge Diffusion CSF_pv = Node(RecursiveRidgeDiffusion(), name='estimate_CSF_pv') CSF_pv.plugin_args = {'sbatch_args': '--mem 6000'} CSF_pv.inputs.ridge_intensities = "dark" CSF_pv.inputs.ridge_filter = "2D" CSF_pv.inputs.orientation = "undefined" CSF_pv.inputs.ang_factor = 1.0 CSF_pv.inputs.min_scale = 0 CSF_pv.inputs.max_scale = 3 CSF_pv.inputs.propagation_model = "diffusion" CSF_pv.inputs.diffusion_factor = 0.5 CSF_pv.inputs.similarity_scale = 0.1 CSF_pv.inputs.neighborhood_size = 4 CSF_pv.inputs.max_iter = 100 CSF_pv.inputs.max_diff = 0.001 CSF_pv.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, CSF_pv.name), CSF_pv, 'output_dir') wf.connect(T1ssNUCirn, 'out_file', CSF_pv, 'input_image') ''' #################################### #### MGDM #### #################################### ''' # Multi-contrast Brain Segmentation MGDM = Node(MGDMSegmentation(), name='MGDM') MGDM.plugin_args = {'sbatch_args': '--mem 7000'} MGDM.inputs.contrast_type1 = "Mprage3T" MGDM.inputs.contrast_type2 = "FLAIR3T" MGDM.inputs.contrast_type3 = "PVDURA" MGDM.inputs.save_data = True MGDM.inputs.atlas_file = atlas wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, MGDM.name), MGDM, 'output_dir') wf.connect(T1ssNUCirn, 'out_file', MGDM, 'contrast_image1') wf.connect(T2ssNUCirn, 'out_file', MGDM, 'contrast_image2') wf.connect(CSF_pv, 'ridge_pv', MGDM, 'contrast_image3') # Enhance Region Contrast ERC = Node(EnhanceRegionContrast(), name='ERC') ERC.plugin_args = {'sbatch_args': '--mem 7000'} ERC.inputs.enhanced_region = "crwm" ERC.inputs.contrast_background = "crgm" ERC.inputs.partial_voluming_distance = 2.0 ERC.inputs.save_data = True ERC.inputs.atlas_file = atlas wf.connect(subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, ERC.name), ERC, 'output_dir') wf.connect(T1ssNUC, 'output_image', ERC, 'intensity_image') wf.connect(MGDM, 'segmentation', ERC, 'segmentation_image') wf.connect(MGDM, 'distance', ERC, 'levelset_boundary_image') # Enhance Region Contrast (2) ERC2 = Node(EnhanceRegionContrast(), name='ERC2') ERC2.plugin_args = {'sbatch_args': '--mem 7000'} ERC2.inputs.enhanced_region = "crwm" ERC2.inputs.contrast_background = "crgm" ERC2.inputs.partial_voluming_distance = 2.0 ERC2.inputs.save_data = True ERC2.inputs.atlas_file = atlas wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, ERC2.name), ERC2, 'output_dir') wf.connect(T2ssNUC, 'output_image', ERC2, 'intensity_image') wf.connect(MGDM, 'segmentation', ERC2, 'segmentation_image') wf.connect(MGDM, 'distance', ERC2, 'levelset_boundary_image') # Define Multi-Region Priors DMRP = Node(DefineMultiRegionPriors(), name='DefineMultRegPriors') DMRP.plugin_args = {'sbatch_args': '--mem 6000'} #DMRP.inputs.defined_region = "ventricle-horns" #DMRP.inputs.definition_method = "closest-distance" DMRP.inputs.distance_offset = 3.0 DMRP.inputs.save_data = True DMRP.inputs.atlas_file = atlas wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, DMRP.name), DMRP, 'output_dir') wf.connect(MGDM, 'segmentation', DMRP, 'segmentation_image') wf.connect(MGDM, 'distance', DMRP, 'levelset_boundary_image') ''' ############################################### #### REMOVE VENTRICLE POSTERIOR #### ############################################### Due to topology constraints, the ventricles are often not fully segmented: here add back all ventricle voxels from the posterior probability (without the topology constraints) ''' # Posterior label PostLabel = Node(Split(), name='PosteriorLabel') PostLabel.inputs.dimension = "t" wf.connect(MGDM, 'labels', PostLabel, 'in_file') # Posterior proba PostProba = Node(Split(), name='PosteriorProba') PostProba.inputs.dimension = "t" wf.connect(MGDM, 'memberships', PostProba, 'in_file') # Threshold binary mask : ventricle label part 1 VentLabel1 = Node(Threshold(), name="VentricleLabel1") VentLabel1.inputs.thresh = 10.5 VentLabel1.inputs.direction = "below" wf.connect(PostLabel, ("out_files", getFirstElement), VentLabel1, "in_file") # Threshold binary mask : ventricle label part 2 VentLabel2 = Node(Threshold(), name="VentricleLabel2") VentLabel2.inputs.thresh = 13.5 VentLabel2.inputs.direction = "above" wf.connect(VentLabel1, "out_file", VentLabel2, "in_file") # Image calculator : ventricle proba VentProba = Node(ImageMaths(), name="VentricleProba") VentProba.inputs.op_string = "-mul" VentProba.inputs.out_file = "ventproba.nii.gz" wf.connect(PostProba, ("out_files", getFirstElement), VentProba, "in_file") wf.connect(VentLabel2, "out_file", VentProba, "in_file2") # Image calculator : remove inter ventricles RmInterVent = Node(ImageMaths(), name="RemoveInterVent") RmInterVent.inputs.op_string = "-sub" RmInterVent.inputs.out_file = "rmintervent.nii.gz" wf.connect(ERC, "region_pv", RmInterVent, "in_file") wf.connect(DMRP, "inter_ventricular_pv", RmInterVent, "in_file2") # Image calculator : add horns AddHorns = Node(ImageMaths(), name="AddHorns") AddHorns.inputs.op_string = "-add" AddHorns.inputs.out_file = "rmvent.nii.gz" wf.connect(RmInterVent, "out_file", AddHorns, "in_file") wf.connect(DMRP, "ventricular_horns_pv", AddHorns, "in_file2") # Image calculator : remove ventricles RmVent = Node(ImageMaths(), name="RemoveVentricles") RmVent.inputs.op_string = "-sub" RmVent.inputs.out_file = "rmvent.nii.gz" wf.connect(AddHorns, "out_file", RmVent, "in_file") wf.connect(VentProba, "out_file", RmVent, "in_file2") # Image calculator : remove internal capsule RmIC = Node(ImageMaths(), name="RemoveInternalCap") RmIC.inputs.op_string = "-sub" RmIC.inputs.out_file = "rmic.nii.gz" wf.connect(RmVent, "out_file", RmIC, "in_file") wf.connect(DMRP, "internal_capsule_pv", RmIC, "in_file2") # Intensity Range Normalization (3) getMaxRmIC = Node(ImageStats(op_string='-r'), name="getMaxRmIC") wf.connect(RmIC, 'out_file', getMaxRmIC, 'in_file') RmICirn = Node(AbcImageMaths(), name="IntensityNormalization5") RmICirn.inputs.op_string = "-div" RmICirn.inputs.out_file = "normRmIC.nii.gz" wf.connect(RmIC, 'out_file', RmICirn, 'in_file') wf.connect(getMaxRmIC, ('out_stat', getElementFromList, 1), RmICirn, "op_value") # Probability To Levelset : WM orientation WM_Orient = Node(ProbabilityToLevelset(), name='WM_Orientation') WM_Orient.plugin_args = {'sbatch_args': '--mem 6000'} WM_Orient.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, WM_Orient.name), WM_Orient, 'output_dir') wf.connect(RmICirn, 'out_file', WM_Orient, 'probability_image') # Recursive Ridge Diffusion : PVS in WM only WM_pvs = Node(RecursiveRidgeDiffusion(), name='PVS_in_WM') WM_pvs.plugin_args = {'sbatch_args': '--mem 6000'} WM_pvs.inputs.ridge_intensities = "bright" WM_pvs.inputs.ridge_filter = "1D" WM_pvs.inputs.orientation = "orthogonal" WM_pvs.inputs.ang_factor = 1.0 WM_pvs.inputs.min_scale = 0 WM_pvs.inputs.max_scale = 3 WM_pvs.inputs.propagation_model = "diffusion" WM_pvs.inputs.diffusion_factor = 1.0 WM_pvs.inputs.similarity_scale = 1.0 WM_pvs.inputs.neighborhood_size = 2 WM_pvs.inputs.max_iter = 100 WM_pvs.inputs.max_diff = 0.001 WM_pvs.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, WM_pvs.name), WM_pvs, 'output_dir') wf.connect(ERC, 'background_proba', WM_pvs, 'input_image') wf.connect(WM_Orient, 'levelset', WM_pvs, 'surface_levelset') wf.connect(RmICirn, 'out_file', WM_pvs, 'loc_prior') # Extract Lesions : extract WM PVS extract_WM_pvs = Node(LesionExtraction(), name='ExtractPVSfromWM') extract_WM_pvs.plugin_args = {'sbatch_args': '--mem 6000'} extract_WM_pvs.inputs.gm_boundary_partial_vol_dist = 1.0 extract_WM_pvs.inputs.csf_boundary_partial_vol_dist = 3.0 extract_WM_pvs.inputs.lesion_clust_dist = 1.0 extract_WM_pvs.inputs.prob_min_thresh = 0.1 extract_WM_pvs.inputs.prob_max_thresh = 0.33 extract_WM_pvs.inputs.small_lesion_size = 4.0 extract_WM_pvs.inputs.save_data = True extract_WM_pvs.inputs.atlas_file = atlas wf.connect(subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, extract_WM_pvs.name), extract_WM_pvs, 'output_dir') wf.connect(WM_pvs, 'propagation', extract_WM_pvs, 'probability_image') wf.connect(MGDM, 'segmentation', extract_WM_pvs, 'segmentation_image') wf.connect(MGDM, 'distance', extract_WM_pvs, 'levelset_boundary_image') wf.connect(RmICirn, 'out_file', extract_WM_pvs, 'location_prior_image') ''' 2nd branch ''' # Image calculator : internal capsule witout ventricules ICwoVent = Node(ImageMaths(), name="ICWithoutVentricules") ICwoVent.inputs.op_string = "-sub" ICwoVent.inputs.out_file = "icwovent.nii.gz" wf.connect(DMRP, "internal_capsule_pv", ICwoVent, "in_file") wf.connect(DMRP, "inter_ventricular_pv", ICwoVent, "in_file2") # Image calculator : remove ventricles IC RmVentIC = Node(ImageMaths(), name="RmVentIC") RmVentIC.inputs.op_string = "-sub" RmVentIC.inputs.out_file = "RmVentIC.nii.gz" wf.connect(ICwoVent, "out_file", RmVentIC, "in_file") wf.connect(VentProba, "out_file", RmVentIC, "in_file2") # Intensity Range Normalization (4) getMaxRmVentIC = Node(ImageStats(op_string='-r'), name="getMaxRmVentIC") wf.connect(RmVentIC, 'out_file', getMaxRmVentIC, 'in_file') RmVentICirn = Node(AbcImageMaths(), name="IntensityNormalization6") RmVentICirn.inputs.op_string = "-div" RmVentICirn.inputs.out_file = "normRmVentIC.nii.gz" wf.connect(RmVentIC, 'out_file', RmVentICirn, 'in_file') wf.connect(getMaxRmVentIC, ('out_stat', getElementFromList, 1), RmVentICirn, "op_value") # Probability To Levelset : IC orientation IC_Orient = Node(ProbabilityToLevelset(), name='IC_Orientation') IC_Orient.plugin_args = {'sbatch_args': '--mem 6000'} IC_Orient.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, IC_Orient.name), IC_Orient, 'output_dir') wf.connect(RmVentICirn, 'out_file', IC_Orient, 'probability_image') # Recursive Ridge Diffusion : PVS in IC only IC_pvs = Node(RecursiveRidgeDiffusion(), name='RecursiveRidgeDiffusion2') IC_pvs.plugin_args = {'sbatch_args': '--mem 6000'} IC_pvs.inputs.ridge_intensities = "bright" IC_pvs.inputs.ridge_filter = "1D" IC_pvs.inputs.orientation = "undefined" IC_pvs.inputs.ang_factor = 1.0 IC_pvs.inputs.min_scale = 0 IC_pvs.inputs.max_scale = 3 IC_pvs.inputs.propagation_model = "diffusion" IC_pvs.inputs.diffusion_factor = 1.0 IC_pvs.inputs.similarity_scale = 1.0 IC_pvs.inputs.neighborhood_size = 2 IC_pvs.inputs.max_iter = 100 IC_pvs.inputs.max_diff = 0.001 IC_pvs.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, IC_pvs.name), IC_pvs, 'output_dir') wf.connect(ERC, 'background_proba', IC_pvs, 'input_image') wf.connect(IC_Orient, 'levelset', IC_pvs, 'surface_levelset') wf.connect(RmVentICirn, 'out_file', IC_pvs, 'loc_prior') # Extract Lesions : extract IC PVS extract_IC_pvs = Node(LesionExtraction(), name='ExtractPVSfromIC') extract_IC_pvs.plugin_args = {'sbatch_args': '--mem 6000'} extract_IC_pvs.inputs.gm_boundary_partial_vol_dist = 1.0 extract_IC_pvs.inputs.csf_boundary_partial_vol_dist = 4.0 extract_IC_pvs.inputs.lesion_clust_dist = 1.0 extract_IC_pvs.inputs.prob_min_thresh = 0.25 extract_IC_pvs.inputs.prob_max_thresh = 0.5 extract_IC_pvs.inputs.small_lesion_size = 4.0 extract_IC_pvs.inputs.save_data = True extract_IC_pvs.inputs.atlas_file = atlas wf.connect(subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, extract_IC_pvs.name), extract_IC_pvs, 'output_dir') wf.connect(IC_pvs, 'propagation', extract_IC_pvs, 'probability_image') wf.connect(MGDM, 'segmentation', extract_IC_pvs, 'segmentation_image') wf.connect(MGDM, 'distance', extract_IC_pvs, 'levelset_boundary_image') wf.connect(RmVentICirn, 'out_file', extract_IC_pvs, 'location_prior_image') ''' 3rd branch ''' # Image calculator : RmInter = Node(ImageMaths(), name="RemoveInterVentricules") RmInter.inputs.op_string = "-sub" RmInter.inputs.out_file = "rminter.nii.gz" wf.connect(ERC2, 'region_pv', RmInter, "in_file") wf.connect(DMRP, "inter_ventricular_pv", RmInter, "in_file2") # Image calculator : AddVentHorns = Node(ImageMaths(), name="AddVentHorns") AddVentHorns.inputs.op_string = "-add" AddVentHorns.inputs.out_file = "rminter.nii.gz" wf.connect(RmInter, 'out_file', AddVentHorns, "in_file") wf.connect(DMRP, "ventricular_horns_pv", AddVentHorns, "in_file2") # Intensity Range Normalization (5) getMaxAddVentHorns = Node(ImageStats(op_string='-r'), name="getMaxAddVentHorns") wf.connect(AddVentHorns, 'out_file', getMaxAddVentHorns, 'in_file') AddVentHornsirn = Node(AbcImageMaths(), name="IntensityNormalization7") AddVentHornsirn.inputs.op_string = "-div" AddVentHornsirn.inputs.out_file = "normAddVentHorns.nii.gz" wf.connect(AddVentHorns, 'out_file', AddVentHornsirn, 'in_file') wf.connect(getMaxAddVentHorns, ('out_stat', getElementFromList, 1), AddVentHornsirn, "op_value") # Extract Lesions : extract White Matter Hyperintensities extract_WMH = Node(LesionExtraction(), name='Extract_WMH') extract_WMH.plugin_args = {'sbatch_args': '--mem 6000'} extract_WMH.inputs.gm_boundary_partial_vol_dist = 1.0 extract_WMH.inputs.csf_boundary_partial_vol_dist = 2.0 extract_WMH.inputs.lesion_clust_dist = 1.0 extract_WMH.inputs.prob_min_thresh = 0.84 extract_WMH.inputs.prob_max_thresh = 0.84 extract_WMH.inputs.small_lesion_size = 4.0 extract_WMH.inputs.save_data = True extract_WMH.inputs.atlas_file = atlas wf.connect(subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, extract_WMH.name), extract_WMH, 'output_dir') wf.connect(ERC2, 'background_proba', extract_WMH, 'probability_image') wf.connect(MGDM, 'segmentation', extract_WMH, 'segmentation_image') wf.connect(MGDM, 'distance', extract_WMH, 'levelset_boundary_image') wf.connect(AddVentHornsirn, 'out_file', extract_WMH, 'location_prior_image') #=========================================================================== # extract_WMH2 = extract_WMH.clone(name='Extract_WMH2') # extract_WMH2.inputs.gm_boundary_partial_vol_dist = 2.0 # wf.connect(subjectList,('subject_id',createOutputDir,wf.base_dir,wf.name,extract_WMH2.name),extract_WMH2,'output_dir') # wf.connect(ERC2,'background_proba',extract_WMH2,'probability_image') # wf.connect(MGDM,'segmentation',extract_WMH2,'segmentation_image') # wf.connect(MGDM,'distance',extract_WMH2,'levelset_boundary_image') # wf.connect(AddVentHornsirn,'out_file',extract_WMH2,'location_prior_image') # # extract_WMH3 = extract_WMH.clone(name='Extract_WMH3') # extract_WMH3.inputs.gm_boundary_partial_vol_dist = 3.0 # wf.connect(subjectList,('subject_id',createOutputDir,wf.base_dir,wf.name,extract_WMH3.name),extract_WMH3,'output_dir') # wf.connect(ERC2,'background_proba',extract_WMH3,'probability_image') # wf.connect(MGDM,'segmentation',extract_WMH3,'segmentation_image') # wf.connect(MGDM,'distance',extract_WMH3,'levelset_boundary_image') # wf.connect(AddVentHornsirn,'out_file',extract_WMH3,'location_prior_image') #=========================================================================== ''' #################################### #### FINDING SMALL WMHs #### #################################### Small round WMHs near the cortex are often missed by the main algorithm, so we're adding this one that takes care of them. ''' # Recursive Ridge Diffusion : round WMH detection round_WMH = Node(RecursiveRidgeDiffusion(), name='round_WMH') round_WMH.plugin_args = {'sbatch_args': '--mem 6000'} round_WMH.inputs.ridge_intensities = "bright" round_WMH.inputs.ridge_filter = "0D" round_WMH.inputs.orientation = "undefined" round_WMH.inputs.ang_factor = 1.0 round_WMH.inputs.min_scale = 1 round_WMH.inputs.max_scale = 4 round_WMH.inputs.propagation_model = "none" round_WMH.inputs.diffusion_factor = 1.0 round_WMH.inputs.similarity_scale = 0.1 round_WMH.inputs.neighborhood_size = 4 round_WMH.inputs.max_iter = 100 round_WMH.inputs.max_diff = 0.001 round_WMH.inputs.save_data = True wf.connect( subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, round_WMH.name), round_WMH, 'output_dir') wf.connect(ERC2, 'background_proba', round_WMH, 'input_image') wf.connect(AddVentHornsirn, 'out_file', round_WMH, 'loc_prior') # Extract Lesions : extract round WMH extract_round_WMH = Node(LesionExtraction(), name='Extract_round_WMH') extract_round_WMH.plugin_args = {'sbatch_args': '--mem 6000'} extract_round_WMH.inputs.gm_boundary_partial_vol_dist = 1.0 extract_round_WMH.inputs.csf_boundary_partial_vol_dist = 2.0 extract_round_WMH.inputs.lesion_clust_dist = 1.0 extract_round_WMH.inputs.prob_min_thresh = 0.33 extract_round_WMH.inputs.prob_max_thresh = 0.33 extract_round_WMH.inputs.small_lesion_size = 6.0 extract_round_WMH.inputs.save_data = True extract_round_WMH.inputs.atlas_file = atlas wf.connect(subjectList, ('subject_id', createOutputDir, wf.base_dir, wf.name, extract_round_WMH.name), extract_round_WMH, 'output_dir') wf.connect(round_WMH, 'ridge_pv', extract_round_WMH, 'probability_image') wf.connect(MGDM, 'segmentation', extract_round_WMH, 'segmentation_image') wf.connect(MGDM, 'distance', extract_round_WMH, 'levelset_boundary_image') wf.connect(AddVentHornsirn, 'out_file', extract_round_WMH, 'location_prior_image') #=========================================================================== # extract_round_WMH2 = extract_round_WMH.clone(name='Extract_round_WMH2') # extract_round_WMH2.inputs.gm_boundary_partial_vol_dist = 2.0 # wf.connect(subjectList,('subject_id',createOutputDir,wf.base_dir,wf.name,extract_round_WMH2.name),extract_round_WMH2,'output_dir') # wf.connect(round_WMH,'ridge_pv',extract_round_WMH2,'probability_image') # wf.connect(MGDM,'segmentation',extract_round_WMH2,'segmentation_image') # wf.connect(MGDM,'distance',extract_round_WMH2,'levelset_boundary_image') # wf.connect(AddVentHornsirn,'out_file',extract_round_WMH2,'location_prior_image') # # extract_round_WMH3 = extract_round_WMH.clone(name='Extract_round_WMH3') # extract_round_WMH3.inputs.gm_boundary_partial_vol_dist = 2.0 # wf.connect(subjectList,('subject_id',createOutputDir,wf.base_dir,wf.name,extract_round_WMH3.name),extract_round_WMH3,'output_dir') # wf.connect(round_WMH,'ridge_pv',extract_round_WMH3,'probability_image') # wf.connect(MGDM,'segmentation',extract_round_WMH3,'segmentation_image') # wf.connect(MGDM,'distance',extract_round_WMH3,'levelset_boundary_image') # wf.connect(AddVentHornsirn,'out_file',extract_round_WMH3,'location_prior_image') #=========================================================================== ''' #################################### #### COMBINE BOTH TYPES #### #################################### Small round WMHs and regular WMH together before thresholding + PVS from white matter and internal capsule ''' # Image calculator : WM + IC DVRS DVRS = Node(ImageMaths(), name="DVRS") DVRS.inputs.op_string = "-max" DVRS.inputs.out_file = "DVRS_map.nii.gz" wf.connect(extract_WM_pvs, 'lesion_score', DVRS, "in_file") wf.connect(extract_IC_pvs, "lesion_score", DVRS, "in_file2") # Image calculator : WMH + round WMH = Node(ImageMaths(), name="WMH") WMH.inputs.op_string = "-max" WMH.inputs.out_file = "WMH_map.nii.gz" wf.connect(extract_WMH, 'lesion_score', WMH, "in_file") wf.connect(extract_round_WMH, "lesion_score", WMH, "in_file2") #=========================================================================== # WMH2 = Node(ImageMaths(), name="WMH2") # WMH2.inputs.op_string = "-max" # WMH2.inputs.out_file = "WMH2_map.nii.gz" # wf.connect(extract_WMH2,'lesion_score',WMH2,"in_file") # wf.connect(extract_round_WMH2,"lesion_score", WMH2, "in_file2") # # WMH3 = Node(ImageMaths(), name="WMH3") # WMH3.inputs.op_string = "-max" # WMH3.inputs.out_file = "WMH3_map.nii.gz" # wf.connect(extract_WMH3,'lesion_score',WMH3,"in_file") # wf.connect(extract_round_WMH3,"lesion_score", WMH3, "in_file2") #=========================================================================== # Image calculator : multiply by boundnary partial volume WMH_mul = Node(ImageMaths(), name="WMH_mul") WMH_mul.inputs.op_string = "-mul" WMH_mul.inputs.out_file = "final_mask.nii.gz" wf.connect(WMH, "out_file", WMH_mul, "in_file") wf.connect(MGDM, "distance", WMH_mul, "in_file2") #=========================================================================== # WMH2_mul = Node(ImageMaths(), name="WMH2_mul") # WMH2_mul.inputs.op_string = "-mul" # WMH2_mul.inputs.out_file = "final_mask.nii.gz" # wf.connect(WMH2,"out_file", WMH2_mul,"in_file") # wf.connect(MGDM,"distance", WMH2_mul, "in_file2") # # WMH3_mul = Node(ImageMaths(), name="WMH3_mul") # WMH3_mul.inputs.op_string = "-mul" # WMH3_mul.inputs.out_file = "final_mask.nii.gz" # wf.connect(WMH3,"out_file", WMH3_mul,"in_file") # wf.connect(MGDM,"distance", WMH3_mul, "in_file2") #=========================================================================== ''' ########################################## #### SEGMENTATION THRESHOLD #### ########################################## A threshold of 0.5 is very conservative, because the final lesion score is the product of two probabilities. This needs to be optimized to a value between 0.25 and 0.5 to balance false negatives (dominant at 0.5) and false positives (dominant at low values). ''' # Threshold binary mask : DVRS_mask = Node(Threshold(), name="DVRS_mask") DVRS_mask.inputs.thresh = 0.25 DVRS_mask.inputs.direction = "below" wf.connect(DVRS, "out_file", DVRS_mask, "in_file") # Threshold binary mask : 025 WMH1_025 = Node(Threshold(), name="WMH1_025") WMH1_025.inputs.thresh = 0.25 WMH1_025.inputs.direction = "below" wf.connect(WMH_mul, "out_file", WMH1_025, "in_file") #=========================================================================== # WMH2_025 = Node(Threshold(), name="WMH2_025") # WMH2_025.inputs.thresh = 0.25 # WMH2_025.inputs.direction = "below" # wf.connect(WMH2_mul,"out_file", WMH2_025, "in_file") # # WMH3_025 = Node(Threshold(), name="WMH3_025") # WMH3_025.inputs.thresh = 0.25 # WMH3_025.inputs.direction = "below" # wf.connect(WMH3_mul,"out_file", WMH3_025, "in_file") #=========================================================================== # Threshold binary mask : 050 WMH1_050 = Node(Threshold(), name="WMH1_050") WMH1_050.inputs.thresh = 0.50 WMH1_050.inputs.direction = "below" wf.connect(WMH_mul, "out_file", WMH1_050, "in_file") #=========================================================================== # WMH2_050 = Node(Threshold(), name="WMH2_050") # WMH2_050.inputs.thresh = 0.50 # WMH2_050.inputs.direction = "below" # wf.connect(WMH2_mul,"out_file", WMH2_050, "in_file") # # WMH3_050 = Node(Threshold(), name="WMH3_050") # WMH3_050.inputs.thresh = 0.50 # WMH3_050.inputs.direction = "below" # wf.connect(WMH3_mul,"out_file", WMH3_050, "in_file") #=========================================================================== # Threshold binary mask : 075 WMH1_075 = Node(Threshold(), name="WMH1_075") WMH1_075.inputs.thresh = 0.75 WMH1_075.inputs.direction = "below" wf.connect(WMH_mul, "out_file", WMH1_075, "in_file") #=========================================================================== # WMH2_075 = Node(Threshold(), name="WMH2_075") # WMH2_075.inputs.thresh = 0.75 # WMH2_075.inputs.direction = "below" # wf.connect(WMH2_mul,"out_file", WMH2_075, "in_file") # # WMH3_075 = Node(Threshold(), name="WMH3_075") # WMH3_075.inputs.thresh = 0.75 # WMH3_075.inputs.direction = "below" # wf.connect(WMH3_mul,"out_file", WMH3_075, "in_file") #=========================================================================== ## Outputs DVRS_Output = Node(IdentityInterface(fields=[ 'mask', 'region', 'lesion_size', 'lesion_proba', 'boundary', 'label', 'score' ]), name='DVRS_Output') wf.connect(DVRS_mask, 'out_file', DVRS_Output, 'mask') WMH_output = Node(IdentityInterface(fields=[ 'mask1025', 'mask1050', 'mask1075', 'mask2025', 'mask2050', 'mask2075', 'mask3025', 'mask3050', 'mask3075' ]), name='WMH_output') wf.connect(WMH1_025, 'out_file', WMH_output, 'mask1025') #wf.connect(WMH2_025,'out_file',WMH_output,'mask2025') #wf.connect(WMH3_025,'out_file',WMH_output,'mask3025') wf.connect(WMH1_050, 'out_file', WMH_output, 'mask1050') #wf.connect(WMH2_050,'out_file',WMH_output,'mask2050') #wf.connect(WMH3_050,'out_file',WMH_output,'mask3050') wf.connect(WMH1_075, 'out_file', WMH_output, 'mask1075') #wf.connect(WMH2_075,'out_file',WMH_output,'mask2070') #wf.connect(WMH3_075,'out_file',WMH_output,'mask3075') return wf
def motion_correction_pipeline(self, **name_maps): if 'struct2align' in self.input_names: StructAlignment = True else: StructAlignment = False pipeline = self.new_pipeline( name='pet_mc', desc=("Given a folder with reconstructed PET data, this " "pipeline will generate a motion corrected PET" "image using information extracted from the MR-based " "motion detection pipeline"), citations=[fsl_cite], name_maps=name_maps) check_pet = pipeline.add( 'check_pet_data', CheckPetMCInputs(), inputs={ 'pet_data': ('pet_data_prepared', directory_format), 'reference': ('ref_brain', nifti_gz_format) }, requirements=[fsl_req.v('5.0.9'), mrtrix_req.v('3.0rc3')]) if self.branch('dynamic_pet_mc'): pipeline.connect_input('fixed_binning_mats', check_pet, 'motion_mats') else: pipeline.connect_input('average_mats', check_pet, 'motion_mats') pipeline.connect_input('correction_factors', check_pet, 'corr_factors') if StructAlignment: struct_reg = pipeline.add('ref2structural_reg', FLIRT(dof=6, cost_func='normmi', cost='normmi', output_type='NIFTI_GZ'), inputs={ 'reference': ('ref_brain', nifti_gz_format), 'in_file': ('struct2align', nifti_gz_format) }, requirements=[fsl_req.v('5.0.9')]) if self.branch('dynamic_pet_mc'): pet_mc = pipeline.add('pet_mc', PetImageMotionCorrection(), inputs={ 'pet_image': (check_pet, 'pet_images'), 'motion_mat': (check_pet, 'motion_mats'), 'pet2ref_mat': (check_pet, 'pet2ref_mat') }, requirements=[fsl_req.v('5.0.9')], iterfield=['pet_image', 'motion_mat']) else: pet_mc = pipeline.add( 'pet_mc', PetImageMotionCorrection(), inputs={'corr_factor': (check_pet, 'corr_factors')}, requirements=[fsl_req.v('5.0.9')], iterfield=['corr_factor', 'pet_image', 'motion_mat']) if StructAlignment: pipeline.connect(struct_reg, 'out_matrix_file', pet_mc, 'structural2ref_regmat') pipeline.connect_input('struct2align', pet_mc, 'structural_image') if self.parameter('PET2MNI_reg'): mni_reg = True else: mni_reg = False if self.branch('dynamic_pet_mc'): merge_mc = pipeline.add( 'merge_pet_mc', fsl.Merge(dimension='t'), inputs={'in_files': (pet_mc, 'pet_mc_image')}, requirements=[fsl_req.v('5.0.9')]) merge_no_mc = pipeline.add( 'merge_pet_no_mc', fsl.Merge(dimension='t'), inputs={'in_files': (pet_mc, 'pet_no_mc_image')}, requirements=[fsl_req.v('5.0.9')]) else: static_mc = pipeline.add('static_mc_generation', StaticPETImageGeneration(), inputs={ 'pet_mc_images': (pet_mc, 'pet_mc_image'), 'pet_no_mc_images': (pet_mc, 'pet_no_mc_image') }, requirements=[fsl_req.v('5.0.9')]) merge_outputs = pipeline.add( 'merge_outputs', Merge(3), inputs={'in1': ('mean_displacement_plot', png_format)}) if not StructAlignment: cropping = pipeline.add( 'pet_cropping', PETFovCropping(x_min=self.parameter('crop_xmin'), x_size=self.parameter('crop_xsize'), y_min=self.parameter('crop_ymin'), y_size=self.parameter('crop_ysize'), z_min=self.parameter('crop_zmin'), z_size=self.parameter('crop_zsize'))) if self.branch('dynamic_pet_mc'): pipeline.connect(merge_mc, 'merged_file', cropping, 'pet_image') else: pipeline.connect(static_mc, 'static_mc', cropping, 'pet_image') cropping_no_mc = pipeline.add( 'pet_no_mc_cropping', PETFovCropping(x_min=self.parameter('crop_xmin'), x_size=self.parameter('crop_xsize'), y_min=self.parameter('crop_ymin'), y_size=self.parameter('crop_ysize'), z_min=self.parameter('crop_zmin'), z_size=self.parameter('crop_zsize'))) if self.branch('dynamic_pet_mc'): pipeline.connect(merge_no_mc, 'merged_file', cropping_no_mc, 'pet_image') else: pipeline.connect(static_mc, 'static_no_mc', cropping_no_mc, 'pet_image') if mni_reg: if self.branch('dynamic_pet_mc'): t_mean = pipeline.add( 'PET_temporal_mean', ImageMaths(op_string='-Tmean'), inputs={'in_file': (cropping, 'pet_cropped')}, requirements=[fsl_req.v('5.0.9')]) reg_tmean2MNI = pipeline.add( 'reg2MNI', AntsRegSyn(num_dimensions=3, transformation='s', out_prefix='reg2MNI', num_threads=4, ref_file=self.parameter('PET_template_MNI')), wall_time=25, requirements=[ants_req.v('2')]) if self.branch('dynamic_pet_mc'): pipeline.connect(t_mean, 'out_file', reg_tmean2MNI, 'input_file') merge_trans = pipeline.add('merge_transforms', Merge(2), inputs={ 'in1': (reg_tmean2MNI, 'warp_file'), 'in2': (reg_tmean2MNI, 'regmat') }, wall_time=1) apply_trans = pipeline.add( 'apply_trans', ApplyTransforms( reference_image=self.parameter('PET_template_MNI'), interpolation='Linear', input_image_type=3), inputs={ 'input_image': (cropping, 'pet_cropped'), 'transforms': (merge_trans, 'out') }, wall_time=7, mem_gb=24, requirements=[ants_req.v('2')]) pipeline.connect(apply_trans, 'output_image', merge_outputs, 'in2'), else: pipeline.connect(cropping, 'pet_cropped', reg_tmean2MNI, 'input_file') pipeline.connect(reg_tmean2MNI, 'reg_file', merge_outputs, 'in2') else: pipeline.connect(cropping, 'pet_cropped', merge_outputs, 'in2') pipeline.connect(cropping_no_mc, 'pet_cropped', merge_outputs, 'in3') else: if self.branch('dynamic_pet_mc'): pipeline.connect(merge_mc, 'merged_file', merge_outputs, 'in2') pipeline.connect(merge_no_mc, 'merged_file', merge_outputs, 'in3') else: pipeline.connect(static_mc, 'static_mc', merge_outputs, 'in2') pipeline.connect(static_mc, 'static_no_mc', merge_outputs, 'in3') # mcflirt = pipeline.add('mcflirt', MCFLIRT()) # 'in_file': (merge_mc_ps, 'merged_file'), # cost='normmi', copy2dir = pipeline.add('copy2dir', CopyToDir(), inputs={'in_files': (merge_outputs, 'out')}) if self.branch('dynamic_pet_mc'): pipeline.connect_output('dynamic_motion_correction_results', copy2dir, 'out_dir') else: pipeline.connect_output('static_motion_correction_results', copy2dir, 'out_dir') return pipeline
def fix_preparation_pipeline(self, **kwargs): pipeline = self.create_pipeline( name='prepare_fix', inputs=[ DatasetSpec('melodic_ica', directory_format), DatasetSpec('filtered_data', nifti_gz_format), DatasetSpec('coreg_to_atlas_mat', text_matrix_format), DatasetSpec('coreg_matrix', text_matrix_format), DatasetSpec('preproc', nifti_gz_format), DatasetSpec('brain', nifti_gz_format), DatasetSpec('coreg_ref_brain', nifti_gz_format), DatasetSpec('mc_par', par_format), DatasetSpec('brain_mask', nifti_gz_format) ], outputs=[ DatasetSpec('fix_dir', directory_format), DatasetSpec('hand_label_noise', text_format) ], desc=("Pipeline to create the right folder structure before " "running FIX"), version=1, citations=[fsl_cite], **kwargs) struct_ants2fsl = pipeline.create_node(ANTs2FSLMatrixConversion(), name='struct_ants2fsl', requirements=[c3d_req]) struct_ants2fsl.inputs.ras2fsl = True struct_ants2fsl.inputs.reference_file = self.parameter('MNI_template') pipeline.connect_input('coreg_to_atlas_mat', struct_ants2fsl, 'itk_file') pipeline.connect_input('coreg_ref_brain', struct_ants2fsl, 'source_file') epi_ants2fsl = pipeline.create_node(ANTs2FSLMatrixConversion(), name='epi_ants2fsl', requirements=[c3d_req]) epi_ants2fsl.inputs.ras2fsl = True pipeline.connect_input('brain', epi_ants2fsl, 'source_file') pipeline.connect_input('coreg_matrix', epi_ants2fsl, 'itk_file') pipeline.connect_input('coreg_ref_brain', epi_ants2fsl, 'reference_file') MNI2t1 = pipeline.create_node(ConvertXFM(), name='MNI2t1', wall_time=5, requirements=[fsl509_req]) MNI2t1.inputs.invert_xfm = True pipeline.connect(struct_ants2fsl, 'fsl_matrix', MNI2t1, 'in_file') struct2epi = pipeline.create_node(ConvertXFM(), name='struct2epi', wall_time=5, requirements=[fsl509_req]) struct2epi.inputs.invert_xfm = True pipeline.connect(epi_ants2fsl, 'fsl_matrix', struct2epi, 'in_file') meanfunc = pipeline.create_node(ImageMaths(op_string='-Tmean', suffix='_mean'), name='meanfunc', wall_time=5, requirements=[fsl509_req]) pipeline.connect_input('preproc', meanfunc, 'in_file') prep_fix = pipeline.create_node(PrepareFIX(), name='prep_fix') pipeline.connect_input('melodic_ica', prep_fix, 'melodic_dir') pipeline.connect_input('coreg_ref_brain', prep_fix, 't1_brain') pipeline.connect_input('mc_par', prep_fix, 'mc_par') pipeline.connect_input('brain_mask', prep_fix, 'epi_brain_mask') pipeline.connect_input('preproc', prep_fix, 'epi_preproc') pipeline.connect_input('filtered_data', prep_fix, 'filtered_epi') pipeline.connect(epi_ants2fsl, 'fsl_matrix', prep_fix, 'epi2t1_mat') pipeline.connect(struct_ants2fsl, 'fsl_matrix', prep_fix, 't12MNI_mat') pipeline.connect(MNI2t1, 'out_file', prep_fix, 'MNI2t1_mat') pipeline.connect(struct2epi, 'out_file', prep_fix, 't12epi_mat') pipeline.connect(meanfunc, 'out_file', prep_fix, 'epi_mean') pipeline.connect_output('fix_dir', prep_fix, 'fix_dir') pipeline.connect_output('hand_label_noise', prep_fix, 'hand_label_file') return pipeline
def fix_preparation_pipeline(self, **name_maps): pipeline = self.new_pipeline( name='prepare_fix', desc=("Pipeline to create the right folder structure before " "running FIX"), citations=[fsl_cite], name_maps=name_maps) if self.branch('coreg_to_tmpl_method', 'ants'): struct_ants2fsl = pipeline.add( 'struct_ants2fsl', ANTs2FSLMatrixConversion(ras2fsl=True), inputs={ 'reference_file': ('template_brain', nifti_gz_format), 'itk_file': ('coreg_to_tmpl_ants_mat', text_matrix_format), 'source_file': ('coreg_ref_brain', nifti_gz_format) }, requirements=[c3d_req.v('1.0.0')]) struct_matrix = (struct_ants2fsl, 'fsl_matrix') else: struct_matrix = ('coreg_to_tmpl_fsl_mat', text_matrix_format) # if self.branch('coreg_method', 'ants'): # epi_ants2fsl = pipeline.add( # 'epi_ants2fsl', # ANTs2FSLMatrixConversion( # ras2fsl=True), # inputs={ # 'source_file': ('brain', nifti_gz_format), # 'itk_file': ('coreg_ants_mat', text_matrix_format), # 'reference_file': ('coreg_ref_brain', nifti_gz_format)}, # requirements=[c3d_req.v('1.0.0')]) MNI2t1 = pipeline.add('MNI2t1', ConvertXFM(invert_xfm=True), inputs={'in_file': struct_matrix}, wall_time=5, requirements=[fsl_req.v('5.0.9')]) struct2epi = pipeline.add( 'struct2epi', ConvertXFM(invert_xfm=True), inputs={'in_file': ('coreg_fsl_mat', text_matrix_format)}, wall_time=5, requirements=[fsl_req.v('5.0.9')]) meanfunc = pipeline.add( 'meanfunc', ImageMaths(op_string='-Tmean', suffix='_mean', output_type='NIFTI_GZ'), inputs={'in_file': ('series_preproc', nifti_gz_format)}, wall_time=5, requirements=[fsl_req.v('5.0.9')]) pipeline.add('prep_fix', PrepareFIX(), inputs={ 'melodic_dir': ('melodic_ica', directory_format), 't1_brain': ('coreg_ref_brain', nifti_gz_format), 'mc_par': ('mc_par', par_format), 'epi_brain_mask': ('brain_mask', nifti_gz_format), 'epi_preproc': ('series_preproc', nifti_gz_format), 'filtered_epi': ('filtered_data', nifti_gz_format), 'epi2t1_mat': ('coreg_fsl_mat', text_matrix_format), 't12MNI_mat': (struct_ants2fsl, 'fsl_matrix'), 'MNI2t1_mat': (MNI2t1, 'out_file'), 't12epi_mat': (struct2epi, 'out_file'), 'epi_mean': (meanfunc, 'out_file') }, outputs={ 'fix_dir': ('fix_dir', directory_format), 'hand_label_noise': ('hand_label_file', text_format) }) return pipeline
def create_t1_based_unwarp(name='unwarp'): """ Unwarp an fMRI time series based on non-linear registration to T1. NOTE: AS IT STANDS THIS METHOD DID NOT PRODUCE ACCEPTABLE RESULTS IF BRAIN COVERAGE IS NOT COMPLETE ON THE EPI IMAGE. ALSO: NEED TO ADD AUTOMATIC READING OF EPI RESOLUTION TO GET """ unwarpflow = pe.Workflow(name=name) inputnode = pe.Node( interface=util.IdentityInterface(fields=['epi', 'T1W']), name='inputspec') outputnode = pe.Node(interface=util.IdentityInterface( fields=['unwarped_func', 'warp_files']), name='outputspec') tmedian = pe.Node(interface=ImageMaths(), name='tmedian') tmedian.inputs.op_string = '-Tmedian' epi_brain_ext = pe.Node(interface=util.Function( function=epi_brain_extract, input_names=['in_file'], output_names=['out_vol', 'out_mask']), name='epi_brain_ext') fast_debias = pe.Node(interface=FAST(), name='FAST_debias') fast_debias.inputs.output_biascorrected = True robex = pe.Node(interface=util.Function( function=my_robex, input_names=['in_file'], output_names=['out_file', 'out_mask']), name='robex') downsample_T1 = pe.Node(MRIConvert(), name='downsample_dti') downsample_T1.inputs.vox_size = (3.438, 3.438, 3.000) downsample_T1.inputs.out_type = 'niigz' contrast_invert = pe.Node(interface=util.Function( function=invert_contrast, input_names=['in_t1_brain', 'in_b0_brain'], output_names=['out_fn']), name='contrast_invert') ants_syn = pe.Node(interface=util.Function( function=my_ants_registration_syn, input_names=['in_T1W', 'in_epi'], output_names=['out_transforms']), name='ants_syn') ants_warp = pe.Node(interface=WarpTimeSeriesImageMultiTransform(), name='ants_warp') '''connections''' # unwarpflow.connect(inputnode, 'T1W', robex, 'in_file') unwarpflow.connect(inputnode, 'T1W', fast_debias, 'in_files') # unwarpflow.connect(robex, 'out_file', fast_debias, 'in_files') unwarpflow.connect(fast_debias, 'restored_image', robex, 'in_file') # unwarpflow.connect(fast_debias, 'restored_image', downsample_T1, 'in_file') unwarpflow.connect(robex, 'out_file', downsample_T1, 'in_file') unwarpflow.connect(downsample_T1, 'out_file', contrast_invert, 'in_t1_brain') unwarpflow.connect(inputnode, 'epi', tmedian, 'in_file') unwarpflow.connect(tmedian, 'out_file', epi_brain_ext, 'in_file') unwarpflow.connect(epi_brain_ext, 'out_vol', contrast_invert, 'in_b0_brain') unwarpflow.connect(contrast_invert, 'out_fn', ants_syn, 'in_T1W') unwarpflow.connect(epi_brain_ext, 'out_vol', ants_syn, 'in_epi') unwarpflow.connect(ants_syn, 'out_transforms', outputnode, 'out_transforms') unwarpflow.connect(inputnode, 'epi', ants_warp, 'input_image') unwarpflow.connect(contrast_invert, 'out_fn', ants_warp, 'reference_image') unwarpflow.connect(ants_syn, 'out_transforms', ants_warp, 'transformation_series') unwarpflow.connect(ants_syn, 'out_transforms', outputnode, 'warp_files') unwarpflow.connect(ants_warp, 'output_image', outputnode, 'unwarped_func') return unwarpflow
def firstlevel_wf(subject_id, sink_directory, name='wmaze_frstlvl_wf'): # Create the frstlvl workflow frstlvl_wf = Workflow(name='frstlvl_wf') # Dictionary holding the wildcard used in datasource info = dict(task_mri_files=[['subject_id', 'wmaze']], motion_noise_files=[['subject_id']]) # Calls the subjectinfo function with the name, onset, duration, and amplitude info subject_info = Node(Function(input_names=['subject_id'], output_names=['output'], function=subjectinfo), name='subject_info') subject_info.inputs.ignore_exception = False subject_info.inputs.subject_id = subject_id # Create another Function node to define the contrasts for the experiment getcontrasts = Node( Function( input_names=['subject_id', 'info'], output_names=['contrasts'], # Calls the function 'get_contrasts' function=get_contrasts), name='getcontrasts') getcontrasts.inputs.ignore_exception = False # Receives subject_id as input getcontrasts.inputs.subject_id = subject_id frstlvl_wf.connect(subject_info, 'output', getcontrasts, 'info') #### subject_info (output) ----> getcontrasts (info) # Create a Function node to substitute names of folders and files created during pipeline getsubs = Node( Function( input_names=['cons'], output_names=['subs'], # Calls the function 'get_subs' function=get_subs), name='getsubs') getsubs.inputs.ignore_exception = False # Receives subject_id as input getsubs.inputs.subject_id = subject_id frstlvl_wf.connect(subject_info, 'output', getsubs, 'info') frstlvl_wf.connect(getcontrasts, 'contrasts', getsubs, 'cons') # Create a datasource node to get the task_mri and motion-noise files datasource = Node(DataGrabber(infields=['subject_id'], outfields=info.keys()), name='datasource') # Indicates the string template to match (in this case, any that match the field template) datasource.inputs.template = '*' # Receives subject_id as an input datasource.inputs.subject_id = subject_id # Base directory to allow branching pathways datasource.inputs.base_directory = os.path.abspath( '/home/data/madlab/data/mri/wmaze/preproc/') datasource.inputs.field_template = dict( task_mri_files='%s/func/smoothed_fullspectrum/_maskfunc2*/*%s*.nii.gz', # Filter regressor noise files motion_noise_files='%s/noise/filter_regressor*.txt') # Inputs from the infields argument ('subject_id') that satisfy the template datasource.inputs.template_args = info # Forces DataGrabber to return data in sorted order when using wildcards datasource.inputs.sort_filelist = True # Do not ignore exceptions datasource.inputs.ignore_exception = False datasource.inputs.raise_on_empty = True # Function to remove last three volumes from functional data # Start from the first volume and end on the -3 volume fslroi_epi = MapNode(ExtractROI(t_min=0, t_size=197), iterfield=['in_file'], name='fslroi_epi') fslroi_epi.output_type = 'NIFTI_GZ' fslroi_epi.terminal_output = 'stream' frstlvl_wf.connect(datasource, 'task_mri_files', fslroi_epi, 'in_file') # Function node to modify the motion and noise files to be single regressors motionnoise = Node( Function( input_names=['subjinfo', 'files'], output_names=['subjinfo'], # Calls the function 'motion_noise' function=motion_noise), name='motionnoise') motionnoise.inputs.ignore_exception = False # The bunch from subject_info function containing regressor names, onsets, durations, and amplitudes frstlvl_wf.connect(subject_info, 'output', motionnoise, 'subjinfo') frstlvl_wf.connect(datasource, 'motion_noise_files', motionnoise, 'files') # Makes a model specification compatible with spm/fsl designers # Requires subjectinfo to be received in the form of a Bunch of a list of Bunch specify_model = Node(SpecifyModel(), name='specify_model') # High-pass filter cutoff in seconds specify_model.inputs.high_pass_filter_cutoff = -1.0 specify_model.inputs.ignore_exception = False # input units in either 'secs' or 'scans' specify_model.inputs.input_units = 'secs' # Time between start of one volume and the start of following volume specify_model.inputs.time_repetition = 2.0 # Editted data files for model -- list of 4D files frstlvl_wf.connect(fslroi_epi, 'roi_file', specify_model, 'functional_runs') # List of event description files in 3 column format corresponding to onsets, durations, and amplitudes frstlvl_wf.connect(motionnoise, 'subjinfo', specify_model, 'subject_info') # Basic interface class generates identity mappings modelfit_inputspec = Node(IdentityInterface(fields=[ 'session_info', 'interscan_interval', 'contrasts', 'film_threshold', 'functional_data', 'bases', 'model_serial_correlations' ], mandatory_inputs=True), name='modelfit_inputspec') # Set bases to a dictionary with a second dictionary setting the value of dgamma derivatives as 'False' modelfit_inputspec.inputs.bases = {'dgamma': {'derivs': False}} # Film threshold modelfit_inputspec.inputs.film_threshold = 0.0 # Interscan_interval modelfit_inputspec.inputs.interscan_interval = 2.0 # Create model serial correlations for Level1Design modelfit_inputspec.inputs.model_serial_correlations = True frstlvl_wf.connect(fslroi_epi, 'roi_file', modelfit_inputspec, 'functional_data') frstlvl_wf.connect(getcontrasts, 'contrasts', modelfit_inputspec, 'contrasts') frstlvl_wf.connect(specify_model, 'session_info', modelfit_inputspec, 'session_info') # Creates a first level SPM design matrix to demonstrate contrasts and motion/noise regressors level1_design = MapNode(Level1Design(), iterfield=['contrasts', 'session_info'], name='level1_design') level1_design.inputs.ignore_exception = False # Inputs the interscan interval (in secs) frstlvl_wf.connect(modelfit_inputspec, 'interscan_interval', level1_design, 'interscan_interval') # Session specific information generated by ``modelgen.SpecifyModel`` frstlvl_wf.connect(modelfit_inputspec, 'session_info', level1_design, 'session_info') # List of contrasts with each contrast being a list of the form -[('name', 'stat', [condition list], [weight list], [session list])]. # If session list is None or not provided, all sessions are used. frstlvl_wf.connect(modelfit_inputspec, 'contrasts', level1_design, 'contrasts') # Name of basis function and options e.g., {'dgamma': {'derivs': True}} frstlvl_wf.connect(modelfit_inputspec, 'bases', level1_design, 'bases') # Option to model serial correlations using an autoregressive estimator (order 1) # Setting this option is only useful in the context of the fsf file frstlvl_wf.connect(modelfit_inputspec, 'model_serial_correlations', level1_design, 'model_serial_correlations') # Create a MapNode to generate a design.mat file for each run generate_model = MapNode(FEATModel(), iterfield=['fsf_file', 'ev_files'], name='generate_model') generate_model.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} generate_model.inputs.ignore_exception = False generate_model.inputs.output_type = 'NIFTI_GZ' generate_model.inputs.terminal_output = 'stream' # File specifying the feat design spec file frstlvl_wf.connect(level1_design, 'fsf_files', generate_model, 'fsf_file') # Event spec files generated by level1design (condition information files) frstlvl_wf.connect(level1_design, 'ev_files', generate_model, 'ev_files') # Create a MapNode to estimate the model using FILMGLS -- fits the design matrix to the voxel timeseries estimate_model = MapNode(FILMGLS(), iterfield=['design_file', 'in_file', 'tcon_file'], name='estimate_model') estimate_model.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} estimate_model.inputs.ignore_exception = False # Susan-smooth mask size estimate_model.inputs.mask_size = 5 estimate_model.inputs.output_type = 'NIFTI_GZ' estimate_model.inputs.results_dir = 'results' # Smooth auto-correlation estimates estimate_model.inputs.smooth_autocorr = True estimate_model.inputs.terminal_output = 'stream' frstlvl_wf.connect(modelfit_inputspec, 'film_threshold', estimate_model, 'threshold') frstlvl_wf.connect(modelfit_inputspec, 'functional_data', estimate_model, 'in_file') # Mat file containing ascii matrix for design frstlvl_wf.connect(generate_model, 'design_file', estimate_model, 'design_file') # Contrast file containing contrast vectors frstlvl_wf.connect(generate_model, 'con_file', estimate_model, 'tcon_file') # Create a merge node to merge the contrasts - necessary for fsl 5.0.7 and greater merge_contrasts = MapNode(Merge(2), iterfield=['in1'], name='merge_contrasts') frstlvl_wf.connect(estimate_model, 'zstats', merge_contrasts, 'in1') # Create a MapNode to transform the z2pval z2pval = MapNode(ImageMaths(), iterfield=['in_file'], name='z2pval') z2pval.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} # Do not ignore exceptions z2pval.inputs.ignore_exception = False # Defines the operation used z2pval.inputs.op_string = '-ztop' # Set the outfile type to nii.gz z2pval.inputs.output_type = 'NIFTI_GZ' # Out-file suffix z2pval.inputs.suffix = '_pval' # Set output to stream in terminal z2pval.inputs.terminal_output = 'stream' frstlvl_wf.connect(merge_contrasts, ('out', pop_lambda), z2pval, 'in_file') # Create an outputspec node using IdentityInterface() to receive information from estimate_model, # merge_contrasts, z2pval, generate_model, and estimate_model modelfit_outputspec = Node(IdentityInterface(fields=[ 'copes', 'varcopes', 'dof_file', 'pfiles', 'parameter_estimates', 'zstats', 'design_image', 'design_file', 'design_cov', 'sigmasquareds' ], mandatory_inputs=True), name='modelfit_outputspec') # All lvl1 cope files frstlvl_wf.connect(estimate_model, 'copes', modelfit_outputspec, 'copes') # All lvl1 varcope files frstlvl_wf.connect(estimate_model, 'varcopes', modelfit_outputspec, 'varcopes') # All zstats across runs frstlvl_wf.connect(merge_contrasts, 'out', modelfit_outputspec, 'zstats') # frstlvl_wf.connect(z2pval, 'out_file', modelfit_outputspec, 'pfiles') # Graphical representation of design matrix frstlvl_wf.connect(generate_model, 'design_image', modelfit_outputspec, 'design_image') # Mat file containing ascii matrix for design frstlvl_wf.connect(generate_model, 'design_file', modelfit_outputspec, 'design_file') # Graphical representation of design covariance frstlvl_wf.connect(generate_model, 'design_cov', modelfit_outputspec, 'design_cov') # Parameter estimates for each column of the design matrix frstlvl_wf.connect(estimate_model, 'param_estimates', modelfit_outputspec, 'parameter_estimates') # Degrees of freedom frstlvl_wf.connect(estimate_model, 'dof_file', modelfit_outputspec, 'dof_file') # Summary of residuals frstlvl_wf.connect(estimate_model, 'sigmasquareds', modelfit_outputspec, 'sigmasquareds') # Create a datasink node to save output from multiple points in the pipeline sinkd = MapNode(DataSink(), iterfield=[ 'substitutions', 'modelfit.contrasts.@copes', 'modelfit.contrasts.@varcopes', 'modelfit.estimates', 'modelfit.contrasts.@zstats' ], name='sinkd') sinkd.inputs.base_directory = sink_directory sinkd.inputs.container = subject_id frstlvl_wf.connect(getsubs, 'subs', sinkd, 'substitutions') frstlvl_wf.connect(modelfit_outputspec, 'parameter_estimates', sinkd, 'modelfit.estimates') frstlvl_wf.connect(modelfit_outputspec, 'sigmasquareds', sinkd, 'modelfit.estimates.@sigsq') frstlvl_wf.connect(modelfit_outputspec, 'dof_file', sinkd, 'modelfit.dofs') frstlvl_wf.connect(modelfit_outputspec, 'copes', sinkd, 'modelfit.contrasts.@copes') frstlvl_wf.connect(modelfit_outputspec, 'varcopes', sinkd, 'modelfit.contrasts.@varcopes') frstlvl_wf.connect(modelfit_outputspec, 'zstats', sinkd, 'modelfit.contrasts.@zstats') frstlvl_wf.connect(modelfit_outputspec, 'design_image', sinkd, 'modelfit.design') frstlvl_wf.connect(modelfit_outputspec, 'design_cov', sinkd, 'modelfit.design.@cov') frstlvl_wf.connect(modelfit_outputspec, 'design_file', sinkd, 'modelfit.design.@matrix') frstlvl_wf.connect(modelfit_outputspec, 'pfiles', sinkd, 'modelfit.contrasts.@pstats') return frstlvl_wf
def firstlevel_wf(subject_id, sink_directory, name='ds008_R2_frstlvl_wf'): frstlvl_wf = Workflow(name='frstlvl_wf') info = dict(task_mri_files=[['subject_id', 'stopsignal']], motion_noise_files=[['subject_id', 'filter_regressor']]) # Create a Function node to define stimulus onsets, etc... for each subject subject_info = Node(Function(input_names=['subject_id'], output_names=['output'], function=subjectinfo), name='subject_info') subject_info.inputs.ignore_exception = False subject_info.inputs.subject_id = subject_id # Create another Function node to define the contrasts for the experiment getcontrasts = Node(Function(input_names=['subject_id'], output_names=['contrasts'], function=get_contrasts), name='getcontrasts') getcontrasts.inputs.ignore_exception = False getcontrasts.inputs.subject_id = subject_id # Create a Function node to substitute names of files created during pipeline getsubs = Node(Function(input_names=['subject_id', 'cons', 'info'], output_names=['subs'], function=get_subs), name='getsubs') getsubs.inputs.ignore_exception = False getsubs.inputs.subject_id = subject_id frstlvl_wf.connect(subject_info, 'output', getsubs, 'info') frstlvl_wf.connect(getcontrasts, 'contrasts', getsubs, 'cons') # Create a datasource node to get the task_mri and motion-noise files datasource = Node(DataGrabber(infields=['subject_id'], outfields=info.keys()), name='datasource') datasource.inputs.template = '*' datasource.inputs.subject_id = subject_id #datasource.inputs.base_directory = os.path.abspath('/scratch/PSB6351_2017/ds008_R2.0.0/preproc/') #datasource.inputs.field_template = dict(task_mri_files='%s/func/realigned/*%s*.nii.gz', # motion_noise_files='%s/noise/%s*.txt') datasource.inputs.base_directory = os.path.abspath( '/scratch/PSB6351_2017/students/salo/data/preproc/') datasource.inputs.field_template = dict( task_mri_files= '%s/preproc/func/smoothed/corr_*_task-%s_*_bold_bet_smooth_mask.nii.gz', motion_noise_files='%s/preproc/noise/%s*.txt') datasource.inputs.template_args = info datasource.inputs.sort_filelist = True datasource.inputs.ignore_exception = False datasource.inputs.raise_on_empty = True # Create a Function node to modify the motion and noise files to be single regressors motionnoise = Node(Function(input_names=['subjinfo', 'files'], output_names=['subjinfo'], function=motion_noise), name='motionnoise') motionnoise.inputs.ignore_exception = False frstlvl_wf.connect(subject_info, 'output', motionnoise, 'subjinfo') frstlvl_wf.connect(datasource, 'motion_noise_files', motionnoise, 'files') # Create a specify model node specify_model = Node(SpecifyModel(), name='specify_model') specify_model.inputs.high_pass_filter_cutoff = 128. specify_model.inputs.ignore_exception = False specify_model.inputs.input_units = 'secs' specify_model.inputs.time_repetition = 2. frstlvl_wf.connect(datasource, 'task_mri_files', specify_model, 'functional_runs') frstlvl_wf.connect(motionnoise, 'subjinfo', specify_model, 'subject_info') # Create an InputSpec node for the modelfit node modelfit_inputspec = Node(IdentityInterface(fields=[ 'session_info', 'interscan_interval', 'contrasts', 'film_threshold', 'functional_data', 'bases', 'model_serial_correlations' ], mandatory_inputs=True), name='modelfit_inputspec') modelfit_inputspec.inputs.bases = {'dgamma': {'derivs': False}} modelfit_inputspec.inputs.film_threshold = 0.0 modelfit_inputspec.inputs.interscan_interval = 2.0 modelfit_inputspec.inputs.model_serial_correlations = True frstlvl_wf.connect(datasource, 'task_mri_files', modelfit_inputspec, 'functional_data') frstlvl_wf.connect(getcontrasts, 'contrasts', modelfit_inputspec, 'contrasts') frstlvl_wf.connect(specify_model, 'session_info', modelfit_inputspec, 'session_info') # Create a level1 design node level1_design = Node(Level1Design(), name='level1_design') level1_design.inputs.ignore_exception = False frstlvl_wf.connect(modelfit_inputspec, 'interscan_interval', level1_design, 'interscan_interval') frstlvl_wf.connect(modelfit_inputspec, 'session_info', level1_design, 'session_info') frstlvl_wf.connect(modelfit_inputspec, 'contrasts', level1_design, 'contrasts') frstlvl_wf.connect(modelfit_inputspec, 'bases', level1_design, 'bases') frstlvl_wf.connect(modelfit_inputspec, 'model_serial_correlations', level1_design, 'model_serial_correlations') # Create a MapNode to generate a model for each run generate_model = MapNode(FEATModel(), iterfield=['fsf_file', 'ev_files'], name='generate_model') generate_model.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} generate_model.inputs.ignore_exception = False generate_model.inputs.output_type = 'NIFTI_GZ' generate_model.inputs.terminal_output = 'stream' frstlvl_wf.connect(level1_design, 'fsf_files', generate_model, 'fsf_file') frstlvl_wf.connect(level1_design, 'ev_files', generate_model, 'ev_files') # Create a MapNode to estimate the model using FILMGLS estimate_model = MapNode(FILMGLS(), iterfield=['design_file', 'in_file', 'tcon_file'], name='estimate_model') frstlvl_wf.connect(generate_model, 'design_file', estimate_model, 'design_file') frstlvl_wf.connect(generate_model, 'con_file', estimate_model, 'tcon_file') frstlvl_wf.connect(modelfit_inputspec, 'functional_data', estimate_model, 'in_file') # Create a merge node to merge the contrasts - necessary for fsl 5.0.7 and greater merge_contrasts = MapNode(Merge(2), iterfield=['in1'], name='merge_contrasts') frstlvl_wf.connect(estimate_model, 'zstats', merge_contrasts, 'in1') # Create a MapNode to transform the z2pval z2pval = MapNode(ImageMaths(), iterfield=['in_file'], name='z2pval') z2pval.inputs.environ = {'FSLOUTPUTTYPE': 'NIFTI_GZ'} z2pval.inputs.ignore_exception = False z2pval.inputs.op_string = '-ztop' z2pval.inputs.output_type = 'NIFTI_GZ' z2pval.inputs.suffix = '_pval' z2pval.inputs.terminal_output = 'stream' frstlvl_wf.connect(merge_contrasts, ('out', pop_lambda), z2pval, 'in_file') # Create an outputspec node modelfit_outputspec = Node(IdentityInterface(fields=[ 'copes', 'varcopes', 'dof_file', 'pfiles', 'parameter_estimates', 'zstats', 'design_image', 'design_file', 'design_cov', 'sigmasquareds' ], mandatory_inputs=True), name='modelfit_outputspec') frstlvl_wf.connect(estimate_model, 'copes', modelfit_outputspec, 'copes') frstlvl_wf.connect(estimate_model, 'varcopes', modelfit_outputspec, 'varcopes') frstlvl_wf.connect(merge_contrasts, 'out', modelfit_outputspec, 'zstats') frstlvl_wf.connect(z2pval, 'out_file', modelfit_outputspec, 'pfiles') frstlvl_wf.connect(generate_model, 'design_image', modelfit_outputspec, 'design_image') frstlvl_wf.connect(generate_model, 'design_file', modelfit_outputspec, 'design_file') frstlvl_wf.connect(generate_model, 'design_cov', modelfit_outputspec, 'design_cov') frstlvl_wf.connect(estimate_model, 'param_estimates', modelfit_outputspec, 'parameter_estimates') frstlvl_wf.connect(estimate_model, 'dof_file', modelfit_outputspec, 'dof_file') frstlvl_wf.connect(estimate_model, 'sigmasquareds', modelfit_outputspec, 'sigmasquareds') # Create a datasink node sinkd = Node(DataSink(), name='sinkd') sinkd.inputs.base_directory = sink_directory sinkd.inputs.container = subject_id frstlvl_wf.connect(getsubs, 'subs', sinkd, 'substitutions') frstlvl_wf.connect(modelfit_outputspec, 'parameter_estimates', sinkd, 'modelfit.estimates') frstlvl_wf.connect(modelfit_outputspec, 'sigmasquareds', sinkd, 'modelfit.estimates.@sigsq') frstlvl_wf.connect(modelfit_outputspec, 'dof_file', sinkd, 'modelfit.dofs') frstlvl_wf.connect(modelfit_outputspec, 'copes', sinkd, 'modelfit.contrasts.@copes') frstlvl_wf.connect(modelfit_outputspec, 'varcopes', sinkd, 'modelfit.contrasts.@varcopes') frstlvl_wf.connect(modelfit_outputspec, 'zstats', sinkd, 'modelfit.contrasts.@zstats') frstlvl_wf.connect(modelfit_outputspec, 'design_image', sinkd, 'modelfit.design') frstlvl_wf.connect(modelfit_outputspec, 'design_cov', sinkd, 'modelfit.design.@cov') frstlvl_wf.connect(modelfit_outputspec, 'design_file', sinkd, 'modelfit.design.@matrix') frstlvl_wf.connect(modelfit_outputspec, 'pfiles', sinkd, 'modelfit.contrasts.@pstats') return frstlvl_wf