From 104e323c3d77a8a2ffac20fb12defb8d81f80e4f Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Fri, 22 Oct 2021 09:51:09 +0200 Subject: [PATCH] fix: void i/o field ``bold_mask`` in bold-to-bold resampling workflow And, not that I'm at it, run black on the file. --- fmriprep/workflows/bold/resampling.py | 652 ++++++++++++++++---------- 1 file changed, 394 insertions(+), 258 deletions(-) diff --git a/fmriprep/workflows/bold/resampling.py b/fmriprep/workflows/bold/resampling.py index d2d7c25e9..1e85b5304 100644 --- a/fmriprep/workflows/bold/resampling.py +++ b/fmriprep/workflows/bold/resampling.py @@ -36,12 +36,7 @@ import nipype.interfaces.workbench as wb -def init_bold_surf_wf( - mem_gb, - surface_spaces, - medial_surface_nan, - name='bold_surf_wf' -): +def init_bold_surf_wf(mem_gb, surface_spaces, medial_surface_nan, name="bold_surf_wf"): """ Sample functional images to FreeSurfer surfaces. @@ -56,7 +51,7 @@ def init_bold_surf_wf( from fmriprep.workflows.bold import init_bold_surf_wf wf = init_bold_surf_wf(mem_gb=0.1, - surface_spaces=['fsnative', 'fsaverage5'], + surface_spaces=["fsnative", "fsaverage5"], medial_surface_nan=False) Parameters @@ -97,82 +92,114 @@ def init_bold_surf_wf( The BOLD time-series were resampled onto the following surfaces (FreeSurfer reconstruction nomenclature): {out_spaces}. -""".format(out_spaces=', '.join(['*%s*' % s for s in surface_spaces])) +""".format( + out_spaces=", ".join(["*%s*" % s for s in surface_spaces]) + ) inputnode = pe.Node( - niu.IdentityInterface(fields=['source_file', 'subject_id', 'subjects_dir', - 't1w2fsnative_xfm']), - name='inputnode') - itersource = pe.Node(niu.IdentityInterface(fields=['target']), name='itersource') - itersource.iterables = [('target', surface_spaces)] + niu.IdentityInterface( + fields=["source_file", "subject_id", "subjects_dir", "t1w2fsnative_xfm"] + ), + name="inputnode", + ) + itersource = pe.Node(niu.IdentityInterface(fields=["target"]), name="itersource") + itersource.iterables = [("target", surface_spaces)] - get_fsnative = pe.Node(FreeSurferSource(), name='get_fsnative', - run_without_submitting=True) + get_fsnative = pe.Node( + FreeSurferSource(), name="get_fsnative", run_without_submitting=True + ) def select_target(subject_id, space): """Get the target subject ID, given a source subject ID and a target space.""" - return subject_id if space == 'fsnative' else space + return subject_id if space == "fsnative" else space - targets = pe.Node(niu.Function(function=select_target), name='targets', - run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) + targets = pe.Node( + niu.Function(function=select_target), + name="targets", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) # Rename the source file to the output space to simplify naming later - rename_src = pe.Node(niu.Rename(format_string='%(subject)s', keep_ext=True), - name='rename_src', run_without_submitting=True, - mem_gb=DEFAULT_MEMORY_MIN_GB) - itk2lta = pe.Node(niu.Function(function=_itk2lta), name="itk2lta", - run_without_submitting=True) + rename_src = pe.Node( + niu.Rename(format_string="%(subject)s", keep_ext=True), + name="rename_src", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) + itk2lta = pe.Node( + niu.Function(function=_itk2lta), name="itk2lta", run_without_submitting=True + ) sampler = pe.MapNode( fs.SampleToSurface( cortex_mask=True, - interp_method='trilinear', - out_type='gii', + interp_method="trilinear", + out_type="gii", override_reg_subj=True, - sampling_method='average', + sampling_method="average", sampling_range=(0, 1, 0.2), - sampling_units='frac', + sampling_units="frac", ), - iterfield=['hemi'], name='sampler', mem_gb=mem_gb * 3) - sampler.inputs.hemi = ['lh', 'rh'] - update_metadata = pe.MapNode(GiftiSetAnatomicalStructure(), iterfield=['in_file'], - name='update_metadata', mem_gb=DEFAULT_MEMORY_MIN_GB) + iterfield=["hemi"], + name="sampler", + mem_gb=mem_gb * 3, + ) + sampler.inputs.hemi = ["lh", "rh"] + update_metadata = pe.MapNode( + GiftiSetAnatomicalStructure(), + iterfield=["in_file"], + name="update_metadata", + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) - outputnode = pe.JoinNode(niu.IdentityInterface(fields=['surfaces', 'target']), - joinsource='itersource', name='outputnode') + outputnode = pe.JoinNode( + niu.IdentityInterface(fields=["surfaces", "target"]), + joinsource="itersource", + name="outputnode", + ) + # fmt:off workflow.connect([ - (inputnode, get_fsnative, [('subject_id', 'subject_id'), - ('subjects_dir', 'subjects_dir')]), - (inputnode, targets, [('subject_id', 'subject_id')]), - (inputnode, rename_src, [('source_file', 'in_file')]), - (inputnode, itk2lta, [('source_file', 'src_file'), - ('t1w2fsnative_xfm', 'in_file')]), - (get_fsnative, itk2lta, [('T1', 'dst_file')]), - (inputnode, sampler, [('subjects_dir', 'subjects_dir'), - ('subject_id', 'subject_id')]), - (itersource, targets, [('target', 'space')]), - (itersource, rename_src, [('target', 'subject')]), - (itk2lta, sampler, [('out', 'reg_file')]), - (targets, sampler, [('out', 'target_subject')]), - (rename_src, sampler, [('out_file', 'source_file')]), - (update_metadata, outputnode, [('out_file', 'surfaces')]), - (itersource, outputnode, [('target', 'target')]), + (inputnode, get_fsnative, [("subject_id", "subject_id"), + ("subjects_dir", "subjects_dir")]), + (inputnode, targets, [("subject_id", "subject_id")]), + (inputnode, rename_src, [("source_file", "in_file")]), + (inputnode, itk2lta, [("source_file", "src_file"), + ("t1w2fsnative_xfm", "in_file")]), + (get_fsnative, itk2lta, [("T1", "dst_file")]), + (inputnode, sampler, [("subjects_dir", "subjects_dir"), + ("subject_id", "subject_id")]), + (itersource, targets, [("target", "space")]), + (itersource, rename_src, [("target", "subject")]), + (itk2lta, sampler, [("out", "reg_file")]), + (targets, sampler, [("out", "target_subject")]), + (rename_src, sampler, [("out_file", "source_file")]), + (update_metadata, outputnode, [("out_file", "surfaces")]), + (itersource, outputnode, [("target", "target")]), ]) + # fmt:on if not medial_surface_nan: - workflow.connect(sampler, 'out_file', update_metadata, 'in_file') + workflow.connect(sampler, "out_file", update_metadata, "in_file") return workflow from niworkflows.interfaces.freesurfer import MedialNaNs + # Refine if medial vertices should be NaNs - medial_nans = pe.MapNode(MedialNaNs(), iterfield=['in_file'], - name='medial_nans', mem_gb=DEFAULT_MEMORY_MIN_GB) + medial_nans = pe.MapNode( + MedialNaNs(), + iterfield=["in_file"], + name="medial_nans", + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) + # fmt:off workflow.connect([ - (inputnode, medial_nans, [('subjects_dir', 'subjects_dir')]), - (sampler, medial_nans, [('out_file', 'in_file')]), - (medial_nans, update_metadata, [('out_file', 'in_file')]), + (inputnode, medial_nans, [("subjects_dir", "subjects_dir")]), + (sampler, medial_nans, [("out_file", "in_file")]), + (medial_nans, update_metadata, [("out_file", "in_file")]), ]) + # fmt:on return workflow @@ -181,7 +208,7 @@ def init_bold_std_trans_wf( mem_gb, omp_nthreads, spaces, - name='bold_std_trans_wf', + name="bold_std_trans_wf", use_compression=True, ): """ @@ -207,8 +234,8 @@ def init_bold_std_trans_wf( mem_gb=3, omp_nthreads=1, spaces=SpatialReferences( - spaces=['MNI152Lin', - ('MNIPediatricAsym', {'cohort': '6'})], + spaces=["MNI152Lin", + ("MNIPediatricAsym", {"cohort": "6"})], checkpoint=True), ) @@ -227,7 +254,7 @@ def init_bold_std_trans_wf( (e.g., ``MNI152Lin``, ``MNI152NLin6Asym``, ``MNIPediatricAsym``), nonstandard references (e.g., ``T1w`` or ``anat``, ``sbref``, ``run``, etc.), or a custom template located in the TemplateFlow root directory. Each ``Reference`` may also contain a spec, which is a - dictionary with template specifications (e.g., a specification of ``{'resolution': 2}`` + dictionary with template specifications (e.g., a specification of ``{"resolution": 2}`` would lead to resampling on a 2mm resolution of the space). name : :obj:`str` Name of workflow (default: ``bold_std_trans_wf``) @@ -300,150 +327,195 @@ def init_bold_std_trans_wf( workflow.__desc__ = """\ The BOLD time-series were resampled into standard space, generating a *preprocessed BOLD run in {tpl} space*. -""".format(tpl=output_references[0]) +""".format( + tpl=output_references[0] + ) elif len(output_references) > 1: workflow.__desc__ = """\ The BOLD time-series were resampled into several standard spaces, correspondingly generating the following *spatially-normalized, preprocessed BOLD runs*: {tpl}. -""".format(tpl=', '.join(output_references)) +""".format( + tpl=", ".join(output_references) + ) inputnode = pe.Node( - niu.IdentityInterface(fields=[ - 'anat2std_xfm', - 'bold_aparc', - 'bold_aseg', - 'bold_mask', - 'bold_split', - 'fieldwarp', - 'hmc_xforms', - 'itk_bold_to_t1', - 'name_source', - 'templates', - ]), - name='inputnode' + niu.IdentityInterface( + fields=[ + "anat2std_xfm", + "bold_aparc", + "bold_aseg", + "bold_mask", + "bold_split", + "fieldwarp", + "hmc_xforms", + "itk_bold_to_t1", + "name_source", + "templates", + ] + ), + name="inputnode", ) iterablesource = pe.Node( - niu.IdentityInterface(fields=['std_target']), name='iterablesource' + niu.IdentityInterface(fields=["std_target"]), name="iterablesource" ) # Generate conversions for every template+spec at the input - iterablesource.iterables = [('std_target', std_vol_references)] + iterablesource.iterables = [("std_target", std_vol_references)] - split_target = pe.Node(niu.Function( - function=_split_spec, input_names=['in_target'], - output_names=['space', 'template', 'spec']), - run_without_submitting=True, name='split_target') + split_target = pe.Node( + niu.Function( + function=_split_spec, + input_names=["in_target"], + output_names=["space", "template", "spec"], + ), + run_without_submitting=True, + name="split_target", + ) - select_std = pe.Node(KeySelect(fields=['anat2std_xfm']), - name='select_std', run_without_submitting=True) + select_std = pe.Node( + KeySelect(fields=["anat2std_xfm"]), + name="select_std", + run_without_submitting=True, + ) - select_tpl = pe.Node(niu.Function(function=_select_template), - name='select_tpl', run_without_submitting=True) + select_tpl = pe.Node( + niu.Function(function=_select_template), + name="select_tpl", + run_without_submitting=True, + ) - gen_ref = pe.Node(GenerateSamplingReference(), name='gen_ref', - mem_gb=0.3) # 256x256x256 * 64 / 8 ~ 150MB) + gen_ref = pe.Node( + GenerateSamplingReference(), name="gen_ref", mem_gb=0.3 + ) # 256x256x256 * 64 / 8 ~ 150MB) - mask_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel'), - name='mask_std_tfm', mem_gb=1) + mask_std_tfm = pe.Node( + ApplyTransforms(interpolation="MultiLabel"), name="mask_std_tfm", mem_gb=1 + ) # Write corrected file in the designated output dir - mask_merge_tfms = pe.Node(niu.Merge(2), name='mask_merge_tfms', run_without_submitting=True, - mem_gb=DEFAULT_MEMORY_MIN_GB) + mask_merge_tfms = pe.Node( + niu.Merge(2), + name="mask_merge_tfms", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) - merge_xforms = pe.Node(niu.Merge(4), name='merge_xforms', - run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) + merge_xforms = pe.Node( + niu.Merge(4), + name="merge_xforms", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) bold_to_std_transform = pe.Node( - MultiApplyTransforms(interpolation="LanczosWindowedSinc", float=True, copy_dtype=True), - name='bold_to_std_transform', mem_gb=mem_gb * 3 * omp_nthreads, n_procs=omp_nthreads) + MultiApplyTransforms( + interpolation="LanczosWindowedSinc", float=True, copy_dtype=True + ), + name="bold_to_std_transform", + mem_gb=mem_gb * 3 * omp_nthreads, + n_procs=omp_nthreads, + ) - merge = pe.Node(Merge(compress=use_compression), name='merge', - mem_gb=mem_gb * 3) + merge = pe.Node(Merge(compress=use_compression), name="merge", mem_gb=mem_gb * 3) # Generate a reference on the target standard space - gen_final_ref = init_bold_reference_wf( - omp_nthreads=omp_nthreads, pre_mask=True) - + gen_final_ref = init_bold_reference_wf(omp_nthreads=omp_nthreads, pre_mask=True) + # fmt:off workflow.connect([ - (iterablesource, split_target, [('std_target', 'in_target')]), - (iterablesource, select_tpl, [('std_target', 'template')]), - (inputnode, select_std, [('anat2std_xfm', 'anat2std_xfm'), - ('templates', 'keys')]), - (inputnode, mask_std_tfm, [('bold_mask', 'input_image')]), - (inputnode, gen_ref, [(('bold_split', _first), 'moving_image')]), - (inputnode, merge_xforms, [('hmc_xforms', 'in4'), - ('fieldwarp', 'in3'), - (('itk_bold_to_t1', _aslist), 'in2')]), - (inputnode, merge, [('name_source', 'header_source')]), - (inputnode, mask_merge_tfms, [(('itk_bold_to_t1', _aslist), 'in2')]), - (inputnode, bold_to_std_transform, [('bold_split', 'input_image')]), - (split_target, select_std, [('space', 'key')]), - (select_std, merge_xforms, [('anat2std_xfm', 'in1')]), - (select_std, mask_merge_tfms, [('anat2std_xfm', 'in1')]), - (split_target, gen_ref, [(('spec', _is_native), 'keep_native')]), - (select_tpl, gen_ref, [('out', 'fixed_image')]), - (merge_xforms, bold_to_std_transform, [('out', 'transforms')]), - (gen_ref, bold_to_std_transform, [('out_file', 'reference_image')]), - (gen_ref, mask_std_tfm, [('out_file', 'reference_image')]), - (mask_merge_tfms, mask_std_tfm, [('out', 'transforms')]), - (mask_std_tfm, gen_final_ref, [('output_image', 'inputnode.bold_mask')]), - (bold_to_std_transform, merge, [('out_files', 'in_files')]), - (merge, gen_final_ref, [('out_file', 'inputnode.bold_file')]), + (iterablesource, split_target, [("std_target", "in_target")]), + (iterablesource, select_tpl, [("std_target", "template")]), + (inputnode, select_std, [("anat2std_xfm", "anat2std_xfm"), + ("templates", "keys")]), + (inputnode, mask_std_tfm, [("bold_mask", "input_image")]), + (inputnode, gen_ref, [(("bold_split", _first), "moving_image")]), + (inputnode, merge_xforms, [("hmc_xforms", "in4"), + ("fieldwarp", "in3"), + (("itk_bold_to_t1", _aslist), "in2")]), + (inputnode, merge, [("name_source", "header_source")]), + (inputnode, mask_merge_tfms, [(("itk_bold_to_t1", _aslist), "in2")]), + (inputnode, bold_to_std_transform, [("bold_split", "input_image")]), + (split_target, select_std, [("space", "key")]), + (select_std, merge_xforms, [("anat2std_xfm", "in1")]), + (select_std, mask_merge_tfms, [("anat2std_xfm", "in1")]), + (split_target, gen_ref, [(("spec", _is_native), "keep_native")]), + (select_tpl, gen_ref, [("out", "fixed_image")]), + (merge_xforms, bold_to_std_transform, [("out", "transforms")]), + (gen_ref, bold_to_std_transform, [("out_file", "reference_image")]), + (gen_ref, mask_std_tfm, [("out_file", "reference_image")]), + (mask_merge_tfms, mask_std_tfm, [("out", "transforms")]), + (mask_std_tfm, gen_final_ref, [("output_image", "inputnode.bold_mask")]), + (bold_to_std_transform, merge, [("out_files", "in_files")]), + (merge, gen_final_ref, [("out_file", "inputnode.bold_file")]), ]) + # fmt:on output_names = [ - 'bold_mask_std', - 'bold_std', - 'bold_std_ref', - 'spatial_reference', - 'template', - ] + freesurfer * ['bold_aseg_std', 'bold_aparc_std'] - - poutputnode = pe.Node(niu.IdentityInterface(fields=output_names), - name='poutputnode') + "bold_mask_std", + "bold_std", + "bold_std_ref", + "spatial_reference", + "template", + ] + freesurfer * ["bold_aseg_std", "bold_aparc_std"] + + poutputnode = pe.Node( + niu.IdentityInterface(fields=output_names), name="poutputnode" + ) + # fmt:off workflow.connect([ # Connecting outputnode (iterablesource, poutputnode, [ - (('std_target', format_reference), 'spatial_reference')]), - (merge, poutputnode, [('out_file', 'bold_std')]), - (gen_final_ref, poutputnode, [('outputnode.ref_image', 'bold_std_ref')]), - (mask_std_tfm, poutputnode, [('output_image', 'bold_mask_std')]), - (select_std, poutputnode, [('key', 'template')]), + (("std_target", format_reference), "spatial_reference")]), + (merge, poutputnode, [("out_file", "bold_std")]), + (gen_final_ref, poutputnode, [("outputnode.ref_image", "bold_std_ref")]), + (mask_std_tfm, poutputnode, [("output_image", "bold_mask_std")]), + (select_std, poutputnode, [("key", "template")]), ]) + # fmt:on if freesurfer: # Sample the parcellation files to functional space - aseg_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel'), - name='aseg_std_tfm', mem_gb=1) - aparc_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel'), - name='aparc_std_tfm', mem_gb=1) - + aseg_std_tfm = pe.Node( + ApplyTransforms(interpolation="MultiLabel"), name="aseg_std_tfm", mem_gb=1 + ) + aparc_std_tfm = pe.Node( + ApplyTransforms(interpolation="MultiLabel"), name="aparc_std_tfm", mem_gb=1 + ) + # fmt:off workflow.connect([ - (inputnode, aseg_std_tfm, [('bold_aseg', 'input_image')]), - (inputnode, aparc_std_tfm, [('bold_aparc', 'input_image')]), - (select_std, aseg_std_tfm, [('anat2std_xfm', 'transforms')]), - (select_std, aparc_std_tfm, [('anat2std_xfm', 'transforms')]), - (gen_ref, aseg_std_tfm, [('out_file', 'reference_image')]), - (gen_ref, aparc_std_tfm, [('out_file', 'reference_image')]), - (aseg_std_tfm, poutputnode, [('output_image', 'bold_aseg_std')]), - (aparc_std_tfm, poutputnode, [('output_image', 'bold_aparc_std')]), + (inputnode, aseg_std_tfm, [("bold_aseg", "input_image")]), + (inputnode, aparc_std_tfm, [("bold_aparc", "input_image")]), + (select_std, aseg_std_tfm, [("anat2std_xfm", "transforms")]), + (select_std, aparc_std_tfm, [("anat2std_xfm", "transforms")]), + (gen_ref, aseg_std_tfm, [("out_file", "reference_image")]), + (gen_ref, aparc_std_tfm, [("out_file", "reference_image")]), + (aseg_std_tfm, poutputnode, [("output_image", "bold_aseg_std")]), + (aparc_std_tfm, poutputnode, [("output_image", "bold_aparc_std")]), ]) + # fmt:on # Connect parametric outputs to a Join outputnode - outputnode = pe.JoinNode(niu.IdentityInterface(fields=output_names), - name='outputnode', joinsource='iterablesource') + outputnode = pe.JoinNode( + niu.IdentityInterface(fields=output_names), + name="outputnode", + joinsource="iterablesource", + ) + # fmt:off workflow.connect([ (poutputnode, outputnode, [(f, f) for f in output_names]), ]) + # fmt:on return workflow -def init_bold_preproc_trans_wf(mem_gb, omp_nthreads, - name='bold_preproc_trans_wf', - use_compression=True, - use_fieldwarp=False, - interpolation='LanczosWindowedSinc'): +def init_bold_preproc_trans_wf( + mem_gb, + omp_nthreads, + name="bold_preproc_trans_wf", + use_compression=True, + use_fieldwarp=False, + interpolation="LanczosWindowedSinc", +): """ Resample in native (original) space. @@ -472,14 +544,12 @@ def init_bold_preproc_trans_wf(mem_gb, omp_nthreads, Include SDC warp in single-shot transform from BOLD to MNI interpolation : :obj:`str` Interpolation type to be used by ANTs' ``applyTransforms`` - (default ``'LanczosWindowedSinc'``) + (default ``"LanczosWindowedSinc"``) Inputs ------ bold_file Individual 3D volumes, not motion corrected - bold_mask - Skull-stripping mask of reference image name_source BOLD series NIfTI file Used to recover original information lost during processing @@ -505,48 +575,60 @@ def init_bold_preproc_trans_wf(mem_gb, omp_nthreads, {transforms}. These resampled BOLD time-series will be referred to as *preprocessed BOLD in original space*, or just *preprocessed BOLD*. -""".format(transforms="""\ +""".format( + transforms="""\ a single, composite transform to correct for head-motion and -susceptibility distortions""" if use_fieldwarp else """\ -the transforms to correct for head-motion""") +susceptibility distortions""" + if use_fieldwarp + else """\ +the transforms to correct for head-motion""" + ) - inputnode = pe.Node(niu.IdentityInterface(fields=[ - 'name_source', 'bold_file', 'bold_mask', 'hmc_xforms', 'fieldwarp']), - name='inputnode' + inputnode = pe.Node( + niu.IdentityInterface( + fields=["name_source", "bold_file", "hmc_xforms", "fieldwarp"] + ), + name="inputnode", ) outputnode = pe.Node( - niu.IdentityInterface(fields=['bold', 'bold_mask', 'bold_ref', 'bold_ref_brain']), - name='outputnode') + niu.IdentityInterface(fields=["bold", "bold_ref", "bold_ref_brain"]), + name="outputnode", + ) - merge_xforms = pe.Node(niu.Merge(2), name='merge_xforms', - run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) + merge_xforms = pe.Node( + niu.Merge(2), + name="merge_xforms", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) bold_transform = pe.Node( MultiApplyTransforms(interpolation=interpolation, copy_dtype=True), - name='bold_transform', mem_gb=mem_gb * 3 * omp_nthreads, n_procs=omp_nthreads) + name="bold_transform", + mem_gb=mem_gb * 3 * omp_nthreads, + n_procs=omp_nthreads, + ) - merge = pe.Node(Merge(compress=use_compression), name='merge', mem_gb=mem_gb * 3) + merge = pe.Node(Merge(compress=use_compression), name="merge", mem_gb=mem_gb * 3) + # fmt:off workflow.connect([ - (inputnode, merge_xforms, [('fieldwarp', 'in1'), - ('hmc_xforms', 'in2')]), - (inputnode, bold_transform, [('bold_file', 'input_image'), - (('bold_file', _first), 'reference_image')]), - (inputnode, merge, [('name_source', 'header_source')]), - (merge_xforms, bold_transform, [('out', 'transforms')]), - (bold_transform, merge, [('out_files', 'in_files')]), - (merge, outputnode, [('out_file', 'bold')]), + (inputnode, merge_xforms, [("fieldwarp", "in1"), + ("hmc_xforms", "in2")]), + (inputnode, bold_transform, [("bold_file", "input_image"), + (("bold_file", _first), "reference_image")]), + (inputnode, merge, [("name_source", "header_source")]), + (merge_xforms, bold_transform, [("out", "transforms")]), + (bold_transform, merge, [("out_files", "in_files")]), + (merge, outputnode, [("out_file", "bold")]), ]) - + # fmt:on return workflow def init_bold_grayords_wf( - grayord_density, - mem_gb, - repetition_time, - name='bold_grayords_wf' + grayord_density, mem_gb, repetition_time, name="bold_grayords_wf" ): """ Sample Grayordinates files onto the fsLR atlas. @@ -559,7 +641,7 @@ def init_bold_grayords_wf( :simple_form: yes from fmriprep.workflows.bold import init_bold_grayords_wf - wf = init_bold_grayords_wf(mem_gb=0.1, grayord_density='91k') + wf = init_bold_grayords_wf(mem_gb=0.1, grayord_density="91k") Parameters ---------- @@ -568,7 +650,7 @@ def init_bold_grayords_wf( mem_gb : :obj:`float` Size of BOLD file in GB name : :obj:`str` - Unique name for the subworkflow (default: ``'bold_grayords_wf'``) + Unique name for the subworkflow (default: ``"bold_grayords_wf"``) Inputs ------ @@ -588,7 +670,7 @@ def init_bold_grayords_wf( cifti_bold : :obj:`str` List of BOLD grayordinates files - (L)eft and (R)ight. cifti_variant : :obj:`str` - Only ``'HCP Grayordinates'`` is currently supported. + Only ``"HCP Grayordinates"`` is currently supported. cifti_metadata : :obj:`str` Path of metadata files corresponding to ``cifti_bold``. cifti_density : :obj:`str` @@ -605,111 +687,169 @@ def init_bold_grayords_wf( *Grayordinates* files [@hcppipelines] containing {density} samples were also generated using the highest-resolution ``fsaverage`` as intermediate standardized surface space. -""".format(density=grayord_density) +""".format( + density=grayord_density + ) - fslr_density, mni_density = ('32k', '2') if grayord_density == '91k' else ('59k', '1') + fslr_density, mni_density = ( + ("32k", "2") if grayord_density == "91k" else ("59k", "1") + ) - inputnode = pe.Node(niu.IdentityInterface(fields=[ - 'bold_std', - 'spatial_reference', - 'subjects_dir', - 'surf_files', - 'surf_refs', - ]), name='inputnode') + inputnode = pe.Node( + niu.IdentityInterface( + fields=[ + "bold_std", + "spatial_reference", + "subjects_dir", + "surf_files", + "surf_refs", + ] + ), + name="inputnode", + ) - outputnode = pe.Node(niu.IdentityInterface(fields=[ - 'cifti_bold', - 'cifti_variant', - 'cifti_metadata', - 'cifti_density', - ]), name='outputnode') + outputnode = pe.Node( + niu.IdentityInterface( + fields=[ + "cifti_bold", + "cifti_variant", + "cifti_metadata", + "cifti_density", + ] + ), + name="outputnode", + ) # extract out to BOLD base - select_std = pe.Node(KeySelect(fields=['bold_std']), name='select_std', - run_without_submitting=True, nohash=True) - select_std.inputs.key = 'MNI152NLin6Asym_res-%s' % mni_density + select_std = pe.Node( + KeySelect(fields=["bold_std"]), + name="select_std", + run_without_submitting=True, + nohash=True, + ) + select_std.inputs.key = "MNI152NLin6Asym_res-%s" % mni_density - select_fs_surf = pe.Node(KeySelect( - fields=['surf_files']), name='select_fs_surf', - run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) - select_fs_surf.inputs.key = 'fsaverage' + select_fs_surf = pe.Node( + KeySelect(fields=["surf_files"]), + name="select_fs_surf", + run_without_submitting=True, + mem_gb=DEFAULT_MEMORY_MIN_GB, + ) + select_fs_surf.inputs.key = "fsaverage" # Setup Workbench command. LR ordering for hemi can be assumed, as it is imposed # by the iterfield of the MapNode in the surface sampling workflow above. - resample = pe.MapNode(wb.MetricResample( - method='ADAP_BARY_AREA', area_metrics=True), name='resample', - iterfield=['in_file', 'out_file', - 'new_sphere', 'new_area', - 'current_sphere', 'current_area']) + resample = pe.MapNode( + wb.MetricResample(method="ADAP_BARY_AREA", area_metrics=True), + name="resample", + iterfield=[ + "in_file", + "out_file", + "new_sphere", + "new_area", + "current_sphere", + "current_area", + ], + ) resample.inputs.current_sphere = [ - str(tf.get('fsaverage', hemi=hemi, density='164k', desc='std', suffix='sphere')) - for hemi in 'LR' + str(tf.get("fsaverage", hemi=hemi, density="164k", desc="std", suffix="sphere")) + for hemi in "LR" ] resample.inputs.current_area = [ - str(tf.get('fsaverage', hemi=hemi, density='164k', desc='vaavg', suffix='midthickness')) - for hemi in 'LR' + str( + tf.get( + "fsaverage", + hemi=hemi, + density="164k", + desc="vaavg", + suffix="midthickness", + ) + ) + for hemi in "LR" ] resample.inputs.new_sphere = [ - str(tf.get('fsLR', space='fsaverage', hemi=hemi, density=fslr_density, suffix='sphere')) - for hemi in 'LR' + str( + tf.get( + "fsLR", + space="fsaverage", + hemi=hemi, + density=fslr_density, + suffix="sphere", + ) + ) + for hemi in "LR" ] resample.inputs.new_area = [ - str(tf.get('fsLR', hemi=hemi, density=fslr_density, desc='vaavg', suffix='midthickness')) - for hemi in 'LR' + str( + tf.get( + "fsLR", + hemi=hemi, + density=fslr_density, + desc="vaavg", + suffix="midthickness", + ) + ) + for hemi in "LR" ] resample.inputs.out_file = [ - 'space-fsLR_hemi-%s_den-%s_bold.gii' % (h, grayord_density) for h in 'LR' + "space-fsLR_hemi-%s_den-%s_bold.gii" % (h, grayord_density) for h in "LR" ] - gen_cifti = pe.Node(GenerateCifti( - volume_target='MNI152NLin6Asym', - surface_target='fsLR', - TR=repetition_time, - surface_density=fslr_density, - ), name="gen_cifti") + gen_cifti = pe.Node( + GenerateCifti( + volume_target="MNI152NLin6Asym", + surface_target="fsLR", + TR=repetition_time, + surface_density=fslr_density, + ), + name="gen_cifti", + ) + # fmt:off workflow.connect([ - (inputnode, gen_cifti, [('subjects_dir', 'subjects_dir')]), - (inputnode, select_std, [('bold_std', 'bold_std'), - ('spatial_reference', 'keys')]), - (inputnode, select_fs_surf, [('surf_files', 'surf_files'), - ('surf_refs', 'keys')]), - (select_fs_surf, resample, [('surf_files', 'in_file')]), - (select_std, gen_cifti, [('bold_std', 'bold_file')]), - (resample, gen_cifti, [('out_file', 'surface_bolds')]), - (gen_cifti, outputnode, [('out_file', 'cifti_bold'), - ('variant', 'cifti_variant'), - ('out_metadata', 'cifti_metadata'), - ('density', 'cifti_density')]), + (inputnode, gen_cifti, [("subjects_dir", "subjects_dir")]), + (inputnode, select_std, [("bold_std", "bold_std"), + ("spatial_reference", "keys")]), + (inputnode, select_fs_surf, [("surf_files", "surf_files"), + ("surf_refs", "keys")]), + (select_fs_surf, resample, [("surf_files", "in_file")]), + (select_std, gen_cifti, [("bold_std", "bold_file")]), + (resample, gen_cifti, [("out_file", "surface_bolds")]), + (gen_cifti, outputnode, [("out_file", "cifti_bold"), + ("variant", "cifti_variant"), + ("out_metadata", "cifti_metadata"), + ("density", "cifti_density")]), ]) + # fmt:on return workflow def _split_spec(in_target): space, spec = in_target - template = space.split(':')[0] + template = space.split(":")[0] return space, template, spec def _select_template(template): from niworkflows.utils.misc import get_template_specs + template, specs = template - template = template.split(':')[0] # Drop any cohort modifier if present + template = template.split(":")[0] # Drop any cohort modifier if present specs = specs.copy() - specs['suffix'] = specs.get('suffix', 'T1w') + specs["suffix"] = specs.get("suffix", "T1w") # Sanitize resolution - res = specs.pop('res', None) or specs.pop('resolution', None) or 'native' - if res != 'native': - specs['resolution'] = res + res = specs.pop("res", None) or specs.pop("resolution", None) or "native" + if res != "native": + specs["resolution"] = res return get_template_specs(template, template_spec=specs)[0] # Map nonstandard resolutions to existing resolutions - specs['resolution'] = 2 + specs["resolution"] = 2 try: out = get_template_specs(template, template_spec=specs) except RuntimeError: - specs['resolution'] = 1 + specs["resolution"] = 1 out = get_template_specs(template, template_spec=specs) return out[0] @@ -726,19 +866,15 @@ def _aslist(in_value): def _is_native(in_value): - return ( - in_value.get('resolution') == 'native' - or in_value.get('res') == 'native' - ) + return in_value.get("resolution") == "native" or in_value.get("res") == "native" def _itk2lta(in_file, src_file, dst_file): import nitransforms as nt from pathlib import Path + out_file = Path("out.lta").absolute() nt.linear.load( - in_file, - fmt="fs" if in_file.endswith(".lta") else "itk", - reference=src_file).to_filename( - out_file, moving=dst_file, fmt="fs") + in_file, fmt="fs" if in_file.endswith(".lta") else "itk", reference=src_file + ).to_filename(out_file, moving=dst_file, fmt="fs") return str(out_file)