2424
2525
2626def init_topup_wf (
27- omp_nthreads = 1 , sloppy = False , debug = False , name = "pepolar_estimate_wf"
27+ grid_reference = 0 ,
28+ omp_nthreads = 1 ,
29+ sloppy = False ,
30+ debug = False ,
31+ name = "pepolar_estimate_wf" ,
2832):
2933 """
3034 Create the PEPOLAR field estimation workflow based on FSL's ``topup``.
@@ -39,6 +43,8 @@ def init_topup_wf(
3943
4044 Parameters
4145 ----------
46+ grid_reference : :obj:`int`
47+ Index of the volume (after flattening) that will be taken for gridding reference.
4248 sloppy : :obj:`bool`
4349 Whether a fast configuration of topup (less accurate) should be applied.
4450 debug : :obj:`bool`
@@ -76,7 +82,7 @@ def init_topup_wf(
7682
7783 from ...utils .misc import front as _front
7884 from ...interfaces .epi import GetReadoutTime
79- from ...interfaces .utils import Flatten
85+ from ...interfaces .utils import Flatten , UniformGrid
8086 from ...interfaces .bspline import TOPUPCoeffReorient
8187 from ..ancillary import init_brainextraction_wf
8288
@@ -104,6 +110,7 @@ def init_topup_wf(
104110 outputnode .inputs .method = "PEB/PEPOLAR (phase-encoding based / PE-POLARity)"
105111
106112 flatten = pe .Node (Flatten (), name = "flatten" )
113+ regrid = pe .Node (UniformGrid (reference = grid_reference ), name = "regrid" )
107114 concat_blips = pe .Node (MergeSeries (), name = "concat_blips" )
108115 readout_time = pe .MapNode (
109116 GetReadoutTime (),
@@ -128,23 +135,18 @@ def init_topup_wf(
128135
129136 brainextraction_wf = init_brainextraction_wf ()
130137
131- def _getfirstpe (in_meta ):
132- if isinstance (in_meta , list ):
133- in_meta = in_meta [0 ]
134- return in_meta ["PhaseEncodingDirection" ]
135-
136138 # fmt: off
137139 workflow .connect ([
138140 (inputnode , flatten , [("in_data" , "in_data" ),
139141 ("metadata" , "in_meta" )]),
140142 (flatten , readout_time , [("out_data" , "in_file" ),
141143 ("out_meta" , "metadata" )]),
142- (flatten , concat_blips , [("out_data" , "in_files " )]),
143- (flatten , topup , [(( "out_meta " , _pe2fsl ), "encoding_direction " )]),
144- (readout_time , topup , [("readout_time" , "readout_times" )]) ,
145- ( concat_blips , topup , [( "out_file " , "in_file " )]),
146- (flatten , fix_coeff , [(( "out_data " , _front ), "fmap_ref" ),
147- (("out_meta " , _getfirstpe ), "pe_dir" )]),
144+ (flatten , regrid , [("out_data" , "in_data " )]),
145+ (regrid , concat_blips , [("out_data " , "in_files " )]),
146+ (readout_time , topup , [("readout_time" , "readout_times" ),
147+ ( "pe_dir_fsl " , "encoding_direction " )]),
148+ (regrid , fix_coeff , [("reference " , "fmap_ref" )] ),
149+ ( readout_time , fix_coeff , [ (("pe_direction " , _front ), "pe_dir" )]),
148150 (topup , fix_coeff , [("out_fieldcoef" , "in_coeff" )]),
149151 (topup , outputnode , [("out_jacs" , "jacobians" ),
150152 ("out_mats" , "xfms" )]),
@@ -158,30 +160,35 @@ def _getfirstpe(in_meta):
158160 if not debug :
159161 # fmt: off
160162 workflow .connect ([
163+ (concat_blips , topup , [("out_file" , "in_file" )]),
161164 (topup , merge_corrected , [("out_corrected" , "in_files" )]),
162165 (topup , outputnode , [("out_field" , "fmap" ),
163166 ("out_warps" , "out_warps" )]),
164167 ])
165168 # fmt: on
166169 return workflow
167170
171+ from nipype .interfaces .afni .preprocess import Volreg
172+ from niworkflows .interfaces .nibabel import SplitSeries
168173 from ...interfaces .bspline import ApplyCoeffsField
169174
175+ realign = pe .Node (
176+ Volreg (args = f"-base { grid_reference } " , outputtype = "NIFTI_GZ" ),
177+ name = "realign_blips" ,
178+ )
179+ split_blips = pe .Node (SplitSeries (), name = "split_blips" )
170180 unwarp = pe .Node (ApplyCoeffsField (), name = "unwarp" )
171181 unwarp .interface ._always_run = True
172182
173- def _getpe (inlist ):
174- if isinstance (inlist , dict ):
175- inlist = [inlist ]
176-
177- return [m ["PhaseEncodingDirection" ] for m in inlist ]
178-
179183 # fmt:off
180184 workflow .connect ([
185+ (concat_blips , realign , [("out_file" , "in_file" )]),
186+ (realign , topup , [("out_file" , "in_file" )]),
181187 (fix_coeff , unwarp , [("out_coeff" , "in_coeff" )]),
182- (flatten , unwarp , [("out_data" , "in_target" ),
183- (("out_meta" , _getpe ), "pe_dir" )]),
184- (readout_time , unwarp , [("readout_time" , "ro_time" )]),
188+ (realign , split_blips , [("out_file" , "in_file" )]),
189+ (split_blips , unwarp , [("out_files" , "in_target" )]),
190+ (readout_time , unwarp , [("readout_time" , "ro_time" ),
191+ ("pe_direction" , "pe_dir" )]),
185192 (unwarp , outputnode , [("out_warp" , "out_warps" ),
186193 ("out_field" , "fmap" )]),
187194 (unwarp , merge_corrected , [("out_corrected" , "in_files" )]),
@@ -343,25 +350,6 @@ def init_3dQwarp_wf(omp_nthreads=1, debug=False, name="pepolar_estimate_wf"):
343350 return workflow
344351
345352
346- def _pe2fsl (metadata ):
347- """
348- Convert ijk notation to xyz.
349-
350- Example
351- -------
352- >>> _pe2fsl([{"PhaseEncodingDirection": "j-"}, {"PhaseEncodingDirection": "i"}])
353- ['y-', 'x']
354-
355- """
356- return [
357- m ["PhaseEncodingDirection" ]
358- .replace ("i" , "x" )
359- .replace ("j" , "y" )
360- .replace ("k" , "z" )
361- for m in metadata
362- ]
363-
364-
365353def _sorted_pe (inlist ):
366354 """
367355 Generate suitable inputs to ``3dQwarp``.
0 commit comments