88
99from nipype import Node , Workflow , MapNode
1010from nipype .interfaces .utility import IdentityInterface , Function , Split
11- from nipype .interfaces .io import SelectFiles , DataSink
11+ from nipype .interfaces .io import SelectFiles , DataSink , DataGrabber
1212from nipype .interfaces .fsl import (
1313 # General usage
14- FSLCommand , ImageStats ,
14+ FSLCommand , ImageStats , ImageMaths
1515 # Preprocessing
1616 SUSAN ,
1717 # Analyses
1818 Level1Design , FEATModel , L2Model , FILMGLS ,
1919 FLAMEO , Randomise , MultipleRegressDesign
2020 )
21- from nipype .interfaces .fsl .utils import ExtractROI , Merge as MergeImages
21+ from nipype .interfaces .fsl .utils import ExtractROI , Merge as FSLMerge
2222from nipype .interfaces .fsl .maths import MathsCommand , MultiImageMaths
2323from nipype .algorithms .modelgen import SpecifyModel
2424
@@ -53,6 +53,10 @@ def get_preprocessing(self):
5353 Returns:
5454 - preprocessing : nipype.WorkFlow
5555 """
56+ # Define workflow
57+ preprocessing = Workflow (base_dir = self .directories .working_dir , name = 'preprocessing' )
58+ preprocessing .config ['execution' ]['stop_on_first_crash' ] = 'true'
59+
5660 # IdentityInterface node - allows to iterate over subjects and runs
5761 information_source = Node (IdentityInterface (
5862 fields = ['subject_id' , 'run_id' ]),
@@ -75,10 +79,22 @@ def get_preprocessing(self):
7579 }
7680 select_files = Node (SelectFiles (templates ), name = 'select_files' )
7781 select_files .inputs .base_directory = self .directories .dataset_dir
78-
79- # DataSink Node - store the wanted results in the wanted directory
80- data_sink = Node (DataSink (), name = 'data_sink' )
81- data_sink .inputs .base_directory = self .directories .output_dir
82+ preprocessing .connect (information_source , 'subject_id' , select_files , 'subject_id' )
83+ preprocessing .connect (information_source , 'run_id' , select_files , 'run_id' )
84+
85+ # ImageMaths - Convert func to float representation
86+ func_to_float = Node (ImageMaths (), name = 'func_to_float' )
87+ func_to_float .inputs .out_data_type = 'float'
88+ func_to_float .inputs .op_string = ''
89+ func_to_float .inputs .suffix = '_dtype'
90+ preprocessing .connect (select_files , 'func' , func_to_float , 'in_file' )
91+
92+ # ImageMaths - Mask the functional image
93+ mask_func = Node (ImageMaths (), name = 'mask_func' )
94+ mask_func .inputs .suffix = '_thresh'
95+ mask_func .inputs .op_string = '-mas'
96+ preprocessing .connect (func_to_float , 'out_file' , mask_func , 'in_file' )
97+ preprocessing .connect (select_files , 'mask' , mask_func , 'in_file2' )
8298
8399 # ImageStats Node - Compute mean value of the 4D data
84100 # -k option adds a mask
@@ -88,10 +104,14 @@ def get_preprocessing(self):
88104 # (i.e.: apply mask then compute stat)
89105 compute_mean = Node (ImageStats (), name = 'compute_mean' )
90106 compute_mean .inputs .op_string = '-k %s -m'
107+ preprocessing .connect (mask_func , 'out_file' , compute_mean , 'in_file' )
91108
92109 # MathsCommand Node - Perform grand-mean intensity normalisation of the entire 4D data
93- intensity_normalization = Node (MathsCommand (), name = 'intensity_normalization' )
94- build_ing_args = lambda x : f'-ing { x } '
110+ intensity_normalization = Node (ImageMaths (), name = 'intensity_normalization' )
111+ build_ing_args = lambda val : '-mul %.10f' % (10000. / val )
112+ preprocessing .connect (mask_func , 'out_file' , intensity_normalization , 'in_file' )
113+ preprocessing .connect (
114+ compute_mean , ('out_stat' , build_ing_args ), intensity_normalization , 'args' )
95115
96116 # ImageStats Node - Compute median of voxel values to derive SUSAN's brightness_threshold
97117 # -k option adds a mask
@@ -101,34 +121,22 @@ def get_preprocessing(self):
101121 # (i.e.: apply mask then compute stat)
102122 compute_median = Node (ImageStats (), name = 'compute_median' )
103123 compute_median .inputs .op_string = '-k %s -p 50'
124+ preprocessing .connect (mask_func , 'out_file' , compute_median , 'in_file' )
104125
105126 # SUSAN Node - smoothing of functional images
106127 # we set brightness_threshold to .75x median of the input file, as performed by fMRIprep
107128 smoothing = Node (SUSAN (), name = 'smoothing' )
108129 smoothing .inputs .fwhm = self .fwhm
109130 compute_brightness_threshold = lambda x : .75 * x
131+ preprocessing .connect (
132+ compute_median , ('out_stat' , compute_brightness_threshold ),
133+ smoothing , 'brightness_threshold' )
134+ preprocessing .connect (intensity_normalization , 'out_file' , smoothing , 'in_file' )
110135
111- # Define workflow
112- preprocessing = Workflow (base_dir = self .directories .working_dir , name = 'preprocessing' )
113- preprocessing .config ['execution' ]['stop_on_first_crash' ] = 'true'
114- preprocessing .connect ([
115- (information_source , select_files , [
116- ('subject_id' , 'subject_id' ), ('run_id' , 'run_id' )
117- ]),
118- (select_files , compute_mean , [('func' , 'in_file' )]),
119- (select_files , compute_mean , [('mask' , 'mask_file' )]),
120- (select_files , intensity_normalization , [('func' , 'in_file' )]),
121- (select_files , compute_median , [('func' , 'in_file' )]),
122- (select_files , compute_median , [('mask' , 'mask_file' )]),
123- (compute_mean , intensity_normalization , [
124- (('out_stat' , build_ing_args ), 'args' )
125- ]),
126- (compute_median , smoothing , [
127- (('out_stat' , compute_brightness_threshold ), 'brightness_threshold' )
128- ]),
129- (intensity_normalization , smoothing , [('out_file' , 'in_file' )]),
130- (smoothing , data_sink , [('smoothed_file' , 'preprocessing.@output_image' )])
131- ])
136+ # DataSink Node - store the wanted results in the wanted directory
137+ data_sink = Node (DataSink (), name = 'data_sink' )
138+ data_sink .inputs .base_directory = self .directories .output_dir
139+ preprocessing .connect (smoothing , 'smoothed_file' , data_sink , 'preprocessing.@output_image' )
132140
133141 # Remove large files, if requested
134142 if Configuration ()['pipelines' ]['remove_unused_data' ]:
@@ -467,11 +475,11 @@ def get_subject_level_analysis(self):
467475 generate_model .inputs .num_copes = len (self .run_list )
468476
469477 # Merge Node - Merge copes files for each subject
470- merge_copes = Node (MergeImages (), name = 'merge_copes' )
478+ merge_copes = Node (FSLMerge (), name = 'merge_copes' )
471479 merge_copes .inputs .dimension = 't'
472480
473481 # Merge Node - Merge varcopes files for each subject
474- merge_varcopes = Node (MergeImages (), name = 'merge_varcopes' )
482+ merge_varcopes = Node (FSLMerge (), name = 'merge_varcopes' )
475483 merge_varcopes .inputs .dimension = 't'
476484
477485 # Split Node - Split mask list to serve them as inputs of the MultiImageMaths node.
@@ -665,11 +673,11 @@ def get_group_level_analysis_sub_workflow(self, method):
665673 )
666674
667675 # Merge Node - Merge cope files
668- merge_copes = Node (MergeImages (), name = 'merge_copes' )
676+ merge_copes = Node (FSLMerge (), name = 'merge_copes' )
669677 merge_copes .inputs .dimension = 't'
670678
671679 # Merge Node - Merge cope files
672- merge_varcopes = Node (MergeImages (), name = 'merge_varcopes' )
680+ merge_varcopes = Node (FSLMerge (), name = 'merge_varcopes' )
673681 merge_varcopes .inputs .dimension = 't'
674682
675683 # Split Node - Split mask list to serve them as inputs of the MultiImageMaths node.
0 commit comments