2020from ..interfaces .masks import SimpleShowMaskRPT
2121from ..interfaces .registration import EstimateReferenceImage
2222from ..interfaces .utils import CopyXForm
23+ from ..utils .connections import listify
2324from ..utils .misc import pass_dummy_scans as _pass_dummy_scans
2425
2526
2930def init_bold_reference_wf (
3031 omp_nthreads ,
3132 bold_file = None ,
33+ sbref_files = None ,
3234 brainmask_thresh = 0.85 ,
3335 pre_mask = False ,
36+ multiecho = False ,
3437 name = "bold_reference_wf" ,
3538 gen_report = False ,
3639):
@@ -51,19 +54,26 @@ def init_bold_reference_wf(
5154
5255 Parameters
5356 ----------
54- omp_nthreads : int
57+ omp_nthreads : :obj:` int`
5558 Maximum number of threads an individual process may use
56- bold_file : str
59+ bold_file : :obj:` str`
5760 BOLD series NIfTI file
61+ sbref_files : :obj:`list` or :obj:`bool`
62+ Single band (as opposed to multi band) reference NIfTI file.
63+ If ``True`` is passed, the workflow is built to accommodate SBRefs,
64+ but the input is left undefined (i.e., it is left open for connection)
5865 brainmask_thresh: :obj:`float`
5966 Lower threshold for the probabilistic brainmask to obtain
6067 the final binary mask (default: 0.85).
61- pre_mask : bool
68+ pre_mask : :obj:` bool`
6269 Indicates whether the ``pre_mask`` input will be set (and thus, step 1
6370 should be skipped).
64- name : str
71+ multiecho : :obj:`bool`
72+ If multiecho data was supplied, data from the first echo
73+ will be selected
74+ name : :obj:`str`
6575 Name of workflow (default: ``bold_reference_wf``)
66- gen_report : bool
76+ gen_report : :obj:` bool`
6777 Whether a mask report node should be appended in the end
6878
6979 Inputs
@@ -104,10 +114,12 @@ def init_bold_reference_wf(
104114
105115 """
106116 workflow = Workflow (name = name )
107- workflow .__desc__ = """\
117+ workflow .__desc__ = f """\
108118 First, a reference volume and its skull-stripped version were generated
109- using a custom methodology of *fMRIPrep*.
119+ { 'from the shortest echo of the BOLD run' * multiecho } using a custom
120+ methodology of *fMRIPrep*.
110121"""
122+
111123 inputnode = pe .Node (
112124 niu .IdentityInterface (
113125 fields = ["bold_file" , "bold_mask" , "dummy_scans" , "sbref_file" ]
@@ -125,6 +137,7 @@ def init_bold_reference_wf(
125137 "ref_image_brain" ,
126138 "bold_mask" ,
127139 "validation_report" ,
140+ "mask_report" ,
128141 ]
129142 ),
130143 name = "outputnode" ,
@@ -134,10 +147,15 @@ def init_bold_reference_wf(
134147 if bold_file is not None :
135148 inputnode .inputs .bold_file = bold_file
136149
137- validate = pe .Node (ValidateImage (), name = "validate" , mem_gb = DEFAULT_MEMORY_MIN_GB )
150+ val_bold = pe .MapNode (
151+ ValidateImage (),
152+ name = "val_bold" ,
153+ mem_gb = DEFAULT_MEMORY_MIN_GB ,
154+ iterfield = ["in_file" ],
155+ )
138156
139157 gen_ref = pe .Node (
140- EstimateReferenceImage (), name = "gen_ref" , mem_gb = 1
158+ EstimateReferenceImage (multiecho = multiecho ), name = "gen_ref" , mem_gb = 1
141159 ) # OE: 128x128x128x50 * 64 / 8 ~ 900MB.
142160 enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf (
143161 brainmask_thresh = brainmask_thresh ,
@@ -151,23 +169,23 @@ def init_bold_reference_wf(
151169 run_without_submitting = True ,
152170 mem_gb = DEFAULT_MEMORY_MIN_GB ,
153171 )
172+ bold_1st = pe .Node (niu .Select (index = [0 ]),
173+ name = "bold_1st" , run_without_submitting = True )
174+ validate_1st = pe .Node (niu .Select (index = [0 ]),
175+ name = "validate_1st" , run_without_submitting = True )
154176
155177 # fmt: off
156178 workflow .connect ([
179+ (inputnode , val_bold , [(("bold_file" , listify ), "in_file" )]),
157180 (inputnode , enhance_and_skullstrip_bold_wf , [
158181 ("bold_mask" , "inputnode.pre_mask" ),
159182 ]),
160- (inputnode , validate , [("bold_file" , "in_file" )]),
161- (inputnode , gen_ref , [("sbref_file" , "sbref_file" )]),
162183 (inputnode , calc_dummy_scans , [("dummy_scans" , "dummy_scans" )]),
163- (validate , gen_ref , [("out_file" , "in_file" )]),
184+ (val_bold , gen_ref , [("out_file" , "in_file" )]),
164185 (gen_ref , enhance_and_skullstrip_bold_wf , [
165186 ("ref_image" , "inputnode.in_file" ),
166187 ]),
167- (validate , outputnode , [
168- ("out_file" , "bold_file" ),
169- ("out_report" , "validation_report" ),
170- ]),
188+ (val_bold , bold_1st , [(("out_file" , listify ), "inlist" )]),
171189 (gen_ref , calc_dummy_scans , [("n_volumes_to_discard" , "algo_dummy_scans" )]),
172190 (calc_dummy_scans , outputnode , [("skip_vols_num" , "skip_vols" )]),
173191 (gen_ref , outputnode , [
@@ -179,9 +197,39 @@ def init_bold_reference_wf(
179197 ("outputnode.mask_file" , "bold_mask" ),
180198 ("outputnode.skull_stripped_file" , "ref_image_brain" ),
181199 ]),
200+ (val_bold , validate_1st , [(("out_report" , listify ), "inlist" )]),
201+ (bold_1st , outputnode , [("out" , "bold_file" )]),
202+ (validate_1st , outputnode , [("out" , "validation_report" )]),
182203 ])
183204 # fmt: on
184205
206+ if sbref_files :
207+ nsbrefs = 0
208+ if sbref_files is not True :
209+ # If not boolean, then it is a list-of or pathlike.
210+ inputnode .inputs .sbref_file = sbref_files
211+ nsbrefs = 1 if isinstance (sbref_files , str ) else len (sbref_files )
212+
213+ val_sbref = pe .MapNode (
214+ ValidateImage (),
215+ name = "val_sbref" ,
216+ mem_gb = DEFAULT_MEMORY_MIN_GB ,
217+ iterfield = ["in_file" ],
218+ )
219+ # fmt: off
220+ workflow .connect ([
221+ (inputnode , val_sbref , [(("sbref_file" , listify ), "in_file" )]),
222+ (val_sbref , gen_ref , [("out_file" , "sbref_file" )]),
223+ ])
224+ # fmt: on
225+
226+ # Edit the boilerplate as the SBRef will be the reference
227+ workflow .__desc__ = f"""\
228+ First, a reference volume and its skull-stripped version were generated
229+ by aligning and averaging{ ' the first echo of' * multiecho }
230+ { nsbrefs or '' } single-band references (SBRefs).
231+ """
232+
185233 if gen_report :
186234 mask_reportlet = pe .Node (SimpleShowMaskRPT (), name = "mask_reportlet" )
187235 # fmt: off
0 commit comments