|
53 | 53 | from ..interfaces.workbench import CreateSignedDistanceVolume
|
54 | 54 |
|
55 | 55 |
|
56 |
| -def init_surface_recon_wf(*, omp_nthreads, hires, name="surface_recon_wf"): |
| 56 | +def init_surface_recon_wf(*, omp_nthreads, hires, fs_reuse_base, name="surface_recon_wf"): |
57 | 57 | r"""
|
58 | 58 | Reconstruct anatomical surfaces using FreeSurfer's ``recon-all``.
|
59 | 59 |
|
@@ -124,6 +124,8 @@ def init_surface_recon_wf(*, omp_nthreads, hires, name="surface_recon_wf"):
|
124 | 124 | Maximum number of threads an individual process may use
|
125 | 125 | hires : bool
|
126 | 126 | Enable sub-millimeter preprocessing in FreeSurfer
|
| 127 | + fs_reuse_base : bool |
| 128 | + Adjust pipeline to reuse base template of existing longitudinal freesurfer |
127 | 129 |
|
128 | 130 | Inputs
|
129 | 131 | ------
|
@@ -222,85 +224,122 @@ def init_surface_recon_wf(*, omp_nthreads, hires, name="surface_recon_wf"):
|
222 | 224 | name="outputnode",
|
223 | 225 | )
|
224 | 226 |
|
225 |
| - recon_config = pe.Node(FSDetectInputs(hires_enabled=hires), name="recon_config") |
226 |
| - |
227 |
| - fov_check = pe.Node(niu.Function(function=_check_cw256), name="fov_check") |
228 |
| - fov_check.inputs.default_flags = ['-noskullstrip', '-noT2pial', '-noFLAIRpial'] |
229 |
| - |
230 |
| - autorecon1 = pe.Node( |
231 |
| - ReconAll(directive="autorecon1", openmp=omp_nthreads), |
232 |
| - name="autorecon1", |
233 |
| - n_procs=omp_nthreads, |
234 |
| - mem_gb=5, |
235 |
| - ) |
236 |
| - autorecon1.interface._can_resume = False |
237 |
| - autorecon1.interface._always_run = True |
238 |
| - |
239 |
| - skull_strip_extern = pe.Node(FSInjectBrainExtracted(), name="skull_strip_extern") |
240 |
| - |
241 | 227 | fsnative2t1w_xfm = pe.Node(
|
242 | 228 | RobustRegister(auto_sens=True, est_int_scale=True), name="fsnative2t1w_xfm"
|
243 | 229 | )
|
244 | 230 | t1w2fsnative_xfm = pe.Node(LTAConvert(out_lta=True, invert=True), name="t1w2fsnative_xfm")
|
245 | 231 |
|
246 |
| - autorecon_resume_wf = init_autorecon_resume_wf(omp_nthreads=omp_nthreads) |
247 | 232 | gifti_surface_wf = init_gifti_surface_wf()
|
248 | 233 |
|
249 | 234 | aseg_to_native_wf = init_segs_to_native_wf()
|
250 | 235 | aparc_to_native_wf = init_segs_to_native_wf(segmentation="aparc_aseg")
|
251 | 236 | refine = pe.Node(RefineBrainMask(), name="refine")
|
252 | 237 |
|
| 238 | + if not fs_reuse_base: |
| 239 | + |
| 240 | + recon_config = pe.Node(FSDetectInputs(hires_enabled=hires), name="recon_config") |
| 241 | + |
| 242 | + fov_check = pe.Node(niu.Function(function=_check_cw256), name="fov_check") |
| 243 | + fov_check.inputs.default_flags = ['-noskullstrip', '-noT2pial', '-noFLAIRpial'] |
| 244 | + |
| 245 | + autorecon1 = pe.Node( |
| 246 | + ReconAll(directive="autorecon1", openmp=omp_nthreads), |
| 247 | + name="autorecon1", |
| 248 | + n_procs=omp_nthreads, |
| 249 | + mem_gb=5, |
| 250 | + ) |
| 251 | + autorecon1.interface._can_resume = False |
| 252 | + autorecon1.interface._always_run = True |
| 253 | + |
| 254 | + skull_strip_extern = pe.Node(FSInjectBrainExtracted(), name="skull_strip_extern") |
| 255 | + |
| 256 | + autorecon_resume_wf = init_autorecon_resume_wf(omp_nthreads=omp_nthreads) |
| 257 | + |
| 258 | + # fmt:off |
| 259 | + workflow.connect( |
| 260 | + # Configuration |
| 261 | + (inputnode, recon_config, [('t1w', 't1w_list'), |
| 262 | + ('t2w', 't2w_list'), |
| 263 | + ('flair', 'flair_list')]), |
| 264 | + # Passing subjects_dir / subject_id enforces serial order |
| 265 | + (inputnode, autorecon1, [('subjects_dir', 'subjects_dir'), |
| 266 | + ('subject_id', 'subject_id')]), |
| 267 | + (autorecon1, skull_strip_extern, [('subjects_dir', 'subjects_dir'), |
| 268 | + ('subject_id', 'subject_id')]), |
| 269 | + (skull_strip_extern, autorecon_resume_wf, [('subjects_dir', 'inputnode.subjects_dir'), |
| 270 | + ('subject_id', 'inputnode.subject_id')]), |
| 271 | + (autorecon_resume_wf, gifti_surface_wf, [ |
| 272 | + ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
| 273 | + ('outputnode.subject_id', 'inputnode.subject_id')]), |
| 274 | + # Reconstruction phases |
| 275 | + (inputnode, autorecon1, [('t1w', 'T1_files')]), |
| 276 | + (inputnode, fov_check, [('t1w', 'in_files')]), |
| 277 | + (fov_check, autorecon1, [('out', 'flags')]), |
| 278 | + (recon_config, autorecon1, [('t2w', 'T2_file'), |
| 279 | + ('flair', 'FLAIR_file'), |
| 280 | + ('hires', 'hires'), |
| 281 | + # First run only (recon-all saves expert options) |
| 282 | + ('mris_inflate', 'mris_inflate')]), |
| 283 | + (inputnode, skull_strip_extern, [('skullstripped_t1', 'in_brain')]), |
| 284 | + (recon_config, autorecon_resume_wf, [('use_t2w', 'inputnode.use_T2'), |
| 285 | + ('use_flair', 'inputnode.use_FLAIR')]), |
| 286 | + (autorecon1, fsnative2t1w_xfm, [('T1', 'source_file')]), |
| 287 | + |
| 288 | + |
| 289 | + (autorecon_resume_wf, aseg_to_native_wf, [ |
| 290 | + ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
| 291 | + ('outputnode.subject_id', 'inputnode.subject_id')]), |
| 292 | + |
| 293 | + (autorecon_resume_wf, aparc_to_native_wf, [ |
| 294 | + ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
| 295 | + ('outputnode.subject_id', 'inputnode.subject_id')]), |
| 296 | + # Output |
| 297 | + (autorecon_resume_wf, outputnode, [('outputnode.subjects_dir', 'subjects_dir'), |
| 298 | + ('outputnode.subject_id', 'subject_id')]), |
| 299 | + ) |
| 300 | + # fmt:on |
| 301 | + else: |
| 302 | + fs_base_inputs = pe.Node(nio.FreeSurferSource()) |
| 303 | + # fmt:off |
| 304 | + workflow.connect([ |
| 305 | + (inputnode, fs_base_inputs, [('subjects_dir', 'subjects_dir'), |
| 306 | + ('subject_id', 'subject_id')]), |
| 307 | + (inputnode, gifti_surface_wf, [ |
| 308 | + ('subjects_dir', 'inputnode.subjects_dir'), |
| 309 | + ('subject_id', 'inputnode.subject_id')]), |
| 310 | + (fs_base_inputs, fsnative2t1w_xfm, [('T1', 'source_file')]), |
| 311 | + |
| 312 | + (inputnode, aparc_to_native_wf, [('corrected_t1', 'inputnode.in_file')]), |
| 313 | + (inputnode, aparc_to_native_wf, [ |
| 314 | + ('subjects_dir', 'inputnode.subjects_dir'), |
| 315 | + ('subject_id', 'inputnode.subject_id')]), |
| 316 | + (fsnative2t1w_xfm, aparc_to_native_wf, [ |
| 317 | + ('out_reg_file', 'inputnode.fsnative2t1w_xfm')]), |
| 318 | + (aseg_to_native_wf, refine, [('outputnode.out_file', 'in_aseg')]), |
| 319 | + |
| 320 | + # Output |
| 321 | + (inputnode, outputnode, [('subjects_dir', 'subjects_dir'), |
| 322 | + ('subject_id', 'subject_id')]), |
| 323 | + ]) |
| 324 | + # fmt:on |
| 325 | + |
253 | 326 | # fmt:off
|
254 | 327 | workflow.connect([
|
255 |
| - # Configuration |
256 |
| - (inputnode, recon_config, [('t1w', 't1w_list'), |
257 |
| - ('t2w', 't2w_list'), |
258 |
| - ('flair', 'flair_list')]), |
259 |
| - # Passing subjects_dir / subject_id enforces serial order |
260 |
| - (inputnode, autorecon1, [('subjects_dir', 'subjects_dir'), |
261 |
| - ('subject_id', 'subject_id')]), |
262 |
| - (autorecon1, skull_strip_extern, [('subjects_dir', 'subjects_dir'), |
263 |
| - ('subject_id', 'subject_id')]), |
264 |
| - (skull_strip_extern, autorecon_resume_wf, [('subjects_dir', 'inputnode.subjects_dir'), |
265 |
| - ('subject_id', 'inputnode.subject_id')]), |
266 |
| - (autorecon_resume_wf, gifti_surface_wf, [ |
267 |
| - ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
268 |
| - ('outputnode.subject_id', 'inputnode.subject_id')]), |
269 |
| - # Reconstruction phases |
270 |
| - (inputnode, autorecon1, [('t1w', 'T1_files')]), |
271 |
| - (inputnode, fov_check, [('t1w', 'in_files')]), |
272 |
| - (fov_check, autorecon1, [('out', 'flags')]), |
273 |
| - (recon_config, autorecon1, [('t2w', 'T2_file'), |
274 |
| - ('flair', 'FLAIR_file'), |
275 |
| - ('hires', 'hires'), |
276 |
| - # First run only (recon-all saves expert options) |
277 |
| - ('mris_inflate', 'mris_inflate')]), |
278 |
| - (inputnode, skull_strip_extern, [('skullstripped_t1', 'in_brain')]), |
279 |
| - (recon_config, autorecon_resume_wf, [('use_t2w', 'inputnode.use_T2'), |
280 |
| - ('use_flair', 'inputnode.use_FLAIR')]), |
281 | 328 | # Construct transform from FreeSurfer conformed image to sMRIPrep
|
282 | 329 | # reoriented image
|
283 | 330 | (inputnode, fsnative2t1w_xfm, [('t1w', 'target_file')]),
|
284 |
| - (autorecon1, fsnative2t1w_xfm, [('T1', 'source_file')]), |
285 | 331 | (fsnative2t1w_xfm, t1w2fsnative_xfm, [('out_reg_file', 'in_lta')]),
|
286 | 332 | # Refine ANTs mask, deriving new mask from FS' aseg
|
287 | 333 | (inputnode, refine, [('corrected_t1', 'in_anat'),
|
288 | 334 | ('ants_segs', 'in_ants')]),
|
289 | 335 | (inputnode, aseg_to_native_wf, [('corrected_t1', 'inputnode.in_file')]),
|
290 |
| - (autorecon_resume_wf, aseg_to_native_wf, [ |
291 |
| - ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
292 |
| - ('outputnode.subject_id', 'inputnode.subject_id')]), |
293 | 336 | (fsnative2t1w_xfm, aseg_to_native_wf, [('out_reg_file', 'inputnode.fsnative2t1w_xfm')]),
|
294 | 337 | (inputnode, aparc_to_native_wf, [('corrected_t1', 'inputnode.in_file')]),
|
295 |
| - (autorecon_resume_wf, aparc_to_native_wf, [ |
296 |
| - ('outputnode.subjects_dir', 'inputnode.subjects_dir'), |
297 |
| - ('outputnode.subject_id', 'inputnode.subject_id')]), |
| 338 | + |
298 | 339 | (fsnative2t1w_xfm, aparc_to_native_wf, [('out_reg_file', 'inputnode.fsnative2t1w_xfm')]),
|
299 | 340 | (aseg_to_native_wf, refine, [('outputnode.out_file', 'in_aseg')]),
|
300 | 341 |
|
301 | 342 | # Output
|
302 |
| - (autorecon_resume_wf, outputnode, [('outputnode.subjects_dir', 'subjects_dir'), |
303 |
| - ('outputnode.subject_id', 'subject_id')]), |
304 | 343 | (gifti_surface_wf, outputnode, [('outputnode.surfaces', 'surfaces'),
|
305 | 344 | ('outputnode.morphometrics', 'morphometrics'),
|
306 | 345 | ('outputnode.midthickness', 'midthickness'),
|
|
0 commit comments