def init_bold_std_trans_wf(freesurfer, mem_gb, omp_nthreads, standard_spaces, name='bold_std_trans_wf', use_compression=True, use_fieldwarp=False): """ This workflow samples functional images into standard space with a single resampling of the original BOLD series. .. workflow:: :graph2use: colored :simple_form: yes from collections import OrderedDict from fmriprep.workflows.bold import init_bold_std_trans_wf wf = init_bold_std_trans_wf( freesurfer=True, mem_gb=3, omp_nthreads=1, standard_spaces=OrderedDict([('MNI152Lin', {}), ('fsaverage', {'density': '10k'})]), ) **Parameters** freesurfer : bool Whether to generate FreeSurfer's aseg/aparc segmentations on BOLD space. mem_gb : float Size of BOLD file in GB omp_nthreads : int Maximum number of threads an individual process may use standard_spaces : OrderedDict Ordered dictionary where keys are TemplateFlow ID strings (e.g., ``MNI152Lin``, ``MNI152NLin6Asym``, ``MNI152NLin2009cAsym``, or ``fsLR``), or paths pointing to custom templates organized in a TemplateFlow-like structure. Values of the dictionary aggregate modifiers (e.g., the value for the key ``MNI152Lin`` could be ``{'resolution': 2}`` if one wants the resampling to be done on the 2mm resolution version of the selected template). name : str Name of workflow (default: ``bold_std_trans_wf``) use_compression : bool Save registered BOLD series as ``.nii.gz`` use_fieldwarp : bool Include SDC warp in single-shot transform from BOLD to MNI **Inputs** anat2std_xfm List of anatomical-to-standard space transforms generated during spatial normalization. bold_aparc FreeSurfer's ``aparc+aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_aseg FreeSurfer's ``aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_mask Skull-stripping mask of reference image bold_split Individual 3D volumes, not motion corrected fieldwarp a :abbr:`DFM (displacements field map)` in ITK format hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format itk_bold_to_t1 Affine transform from ``ref_bold_brain`` to T1 space (ITK format) name_source BOLD series NIfTI file Used to recover original information lost during processing templates List of templates that were applied as targets during spatial normalization. **Outputs** - Two outputnodes are available. One output node (with name ``poutputnode``) will be parameterized in a Nipype sense (see `Nipype iterables <https://miykael.github.io/nipype_tutorial/notebooks/basic_iteration.html>`__), and a second node (``outputnode``) will collapse the parameterized outputs into synchronous lists of the following fields: bold_std BOLD series, resampled to template space bold_std_ref Reference, contrast-enhanced summary of the BOLD series, resampled to template space bold_mask_std BOLD series mask in template space bold_aseg_std FreeSurfer's ``aseg.mgz`` atlas, in template space at the BOLD resolution (only if ``recon-all`` was run) bold_aparc_std FreeSurfer's ``aparc+aseg.mgz`` atlas, in template space at the BOLD resolution (only if ``recon-all`` was run) templates Template identifiers synchronized correspondingly to previously described outputs. """ # Filter ``standard_spaces`` vol_std_spaces = [ k for k in standard_spaces.keys() if not k.startswith('fs') ] workflow = Workflow(name=name) if len(vol_std_spaces) == 1: workflow.__desc__ = """\ The BOLD time-series were resampled into standard space, generating a *preprocessed BOLD run in {tpl} space*. """.format(tpl=vol_std_spaces) else: 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(vol_std_spaces)) 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') select_std = pe.Node(KeySelect(fields=['resolution', 'anat2std_xfm']), name='select_std', run_without_submitting=True) select_std.inputs.resolution = [ v.get('resolution') or v.get('res') or 'native' for k, v in list(standard_spaces.items()) if k in vol_std_spaces ] select_std.iterables = ('key', vol_std_spaces) select_tpl = pe.Node(niu.Function(function=_select_template), name='select_tpl', run_without_submitting=True) select_tpl.inputs.template_specs = standard_spaces gen_ref = pe.Node(GenerateSamplingReference(), name='gen_ref', mem_gb=0.3) # 256x256x256 * 64 / 8 ~ 150MB) mask_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True), 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) workflow.connect([ (inputnode, select_std, [('templates', 'keys'), ('anat2std_xfm', 'anat2std_xfm')]), (inputnode, mask_std_tfm, [('bold_mask', 'input_image')]), (inputnode, gen_ref, [(('bold_split', _first), 'moving_image')]), (inputnode, mask_merge_tfms, [(('itk_bold_to_t1', _aslist), 'in2')]), (select_std, select_tpl, [('key', 'template')]), (select_std, mask_merge_tfms, [('anat2std_xfm', 'in1')]), (select_std, gen_ref, [(('resolution', _is_native), 'keep_native')]), (select_tpl, gen_ref, [('out', 'fixed_image')]), (mask_merge_tfms, mask_std_tfm, [('out', 'transforms')]), (gen_ref, mask_std_tfm, [('out_file', 'reference_image')]), ]) nxforms = 4 if use_fieldwarp else 3 merge_xforms = pe.Node(niu.Merge(nxforms), name='merge_xforms', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([(inputnode, merge_xforms, [('hmc_xforms', 'in%d' % nxforms)])]) if use_fieldwarp: workflow.connect([(inputnode, merge_xforms, [('fieldwarp', 'in3')])]) 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) merge = pe.Node(Merge(compress=use_compression), name='merge', mem_gb=mem_gb * 3) # Generate a reference on the target T1w space gen_final_ref = init_bold_reference_wf(omp_nthreads=omp_nthreads, pre_mask=True) workflow.connect([ (inputnode, merge_xforms, [(('itk_bold_to_t1', _aslist), 'in2')]), (inputnode, merge, [('name_source', 'header_source')]), (inputnode, bold_to_std_transform, [('bold_split', 'input_image')]), (select_std, merge_xforms, [('anat2std_xfm', 'in1')]), (merge_xforms, bold_to_std_transform, [('out', 'transforms')]), (gen_ref, bold_to_std_transform, [('out_file', 'reference_image')]), (bold_to_std_transform, merge, [('out_files', 'in_files')]), (merge, gen_final_ref, [('out_file', 'inputnode.bold_file')]), (mask_std_tfm, gen_final_ref, [('output_image', 'inputnode.bold_mask') ]), ]) # Connect output nodes output_names = ['bold_std', 'bold_std_ref', 'bold_mask_std', 'templates'] if freesurfer: output_names += ['bold_aseg_std', 'bold_aparc_std'] # poutputnode - parametric output node poutputnode = pe.Node(niu.IdentityInterface(fields=output_names), name='poutputnode') workflow.connect([ (gen_final_ref, poutputnode, [('outputnode.ref_image', 'bold_std_ref') ]), (merge, poutputnode, [('out_file', 'bold_std')]), (mask_std_tfm, poutputnode, [('output_image', 'bold_mask_std')]), (select_std, poutputnode, [('key', 'templates')]), ]) if freesurfer: # Sample the parcellation files to functional space aseg_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True), name='aseg_std_tfm', mem_gb=1) aparc_std_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True), name='aparc_std_tfm', mem_gb=1) 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')]), ]) # Connect outputnode to the parameterized outputnode outputnode = pe.JoinNode(niu.IdentityInterface(fields=output_names), name='outputnode', joinsource='select_std') workflow.connect([(poutputnode, outputnode, [(f, f) for f in output_names])]) return workflow
def init_bold_preproc_trans_wf(mem_gb, omp_nthreads, name='bold_preproc_trans_wf', use_compression=True, use_fieldwarp=False, split_file=False, interpolation='LanczosWindowedSinc'): """ This workflow resamples the input fMRI in its native (original) space in a "single shot" from the original BOLD series. .. workflow:: :graph2use: colored :simple_form: yes from fmriprep.workflows.bold import init_bold_preproc_trans_wf wf = init_bold_preproc_trans_wf(mem_gb=3, omp_nthreads=1) **Parameters** mem_gb : float Size of BOLD file in GB omp_nthreads : int Maximum number of threads an individual process may use name : str Name of workflow (default: ``bold_std_trans_wf``) use_compression : bool Save registered BOLD series as ``.nii.gz`` use_fieldwarp : bool Include SDC warp in single-shot transform from BOLD to MNI split_file : bool Whether the input file should be splitted (it is a 4D file) or it is a list of 3D files (default ``False``, do not split) interpolation : str Interpolation type to be used by ANTs' ``applyTransforms`` (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 hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format fieldwarp a :abbr:`DFM (displacements field map)` in ITK format **Outputs** bold BOLD series, resampled in native space, including all preprocessing bold_mask BOLD series mask calculated with the new time-series bold_ref BOLD reference image: an average-like 3D image of the time-series bold_ref_brain Same as ``bold_ref``, but once the brain mask has been applied """ workflow = Workflow(name=name) workflow.__desc__ = """\ The BOLD time-series (including slice-timing correction when applied) were resampled onto their original, native space by applying {transforms}. These resampled BOLD time-series will be referred to as *preprocessed BOLD in original space*, or just *preprocessed BOLD*. """.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""") inputnode = pe.Node(niu.IdentityInterface(fields=[ 'name_source', 'bold_file', 'bold_mask', 'hmc_xforms', 'fieldwarp' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['bold', 'bold_mask', 'bold_ref', 'bold_ref_brain']), name='outputnode') bold_transform = pe.Node(MultiApplyTransforms(interpolation=interpolation, float=True, copy_dtype=True), 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) # Generate a new BOLD reference bold_reference_wf = init_bold_reference_wf(omp_nthreads=omp_nthreads) bold_reference_wf.__desc__ = None # Unset description to avoid second appearance workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), (bold_transform, merge, [('out_files', 'in_files')]), (merge, bold_reference_wf, [('out_file', 'inputnode.bold_file')]), (merge, outputnode, [('out_file', 'bold')]), (bold_reference_wf, outputnode, [('outputnode.ref_image', 'bold_ref'), ('outputnode.ref_image_brain', 'bold_ref_brain'), ('outputnode.bold_mask', 'bold_mask')]), ]) # Input file is not splitted if split_file: bold_split = pe.Node(FSLSplit(dimension='t'), name='bold_split', mem_gb=mem_gb * 3) workflow.connect([(inputnode, bold_split, [('bold_file', 'in_file')]), (bold_split, bold_transform, [ ('out_files', 'input_image'), (('out_files', _first), 'reference_image'), ])]) else: workflow.connect([ (inputnode, bold_transform, [('bold_file', 'input_image'), (('bold_file', _first), 'reference_image')]), ]) if use_fieldwarp: merge_xforms = pe.Node(niu.Merge(2), name='merge_xforms', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([ (inputnode, merge_xforms, [('fieldwarp', 'in1'), ('hmc_xforms', 'in2')]), (merge_xforms, bold_transform, [('out', 'transforms')]), ]) else: def _aslist(val): return [val] workflow.connect([ (inputnode, bold_transform, [(('hmc_xforms', _aslist), 'transforms')]), ]) # Code ready to generate a pre/post processing report # bold_bold_report_wf = init_bold_preproc_report_wf( # mem_gb=mem_gb['resampled'], # reportlets_dir=reportlets_dir # ) # workflow.connect([ # (inputnode, bold_bold_report_wf, [ # ('bold_file', 'inputnode.name_source'), # ('bold_file', 'inputnode.in_pre')]), # This should be after STC # (bold_bold_trans_wf, bold_bold_report_wf, [ # ('outputnode.bold', 'inputnode.in_post')]), # ]) return workflow
def init_bold_std_trans_wf( freesurfer, mem_gb, omp_nthreads, spaces, name='bold_std_trans_wf', use_compression=True, use_fieldwarp=False, ): """ Sample fMRI into standard space with a single-step resampling of the original BOLD series. .. important:: This workflow provides two outputnodes. One output node (with name ``poutputnode``) will be parameterized in a Nipype sense (see `Nipype iterables <https://miykael.github.io/nipype_tutorial/notebooks/basic_iteration.html>`__), and a second node (``outputnode``) will collapse the parameterized outputs into synchronous lists of the output fields listed below. Workflow Graph .. workflow:: :graph2use: colored :simple_form: yes from niworkflows.utils.spaces import SpatialReferences from fmriprep_rodents.workflows.bold import init_bold_std_trans_wf wf = init_bold_std_trans_wf( freesurfer=True, mem_gb=3, omp_nthreads=1, spaces=SpatialReferences( spaces=['MNI152Lin', ('MNIPediatricAsym', {'cohort': '6'})], checkpoint=True), ) Parameters ---------- freesurfer : :obj:`bool` Whether to generate FreeSurfer's aseg/aparc segmentations on BOLD space. mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use spaces : :py:class:`~niworkflows.utils.spaces.SpatialReferences` A container for storing, organizing, and parsing spatial normalizations. Composed of :py:class:`~niworkflows.utils.spaces.Reference` objects representing spatial references. Each ``Reference`` contains a space, which is a string of either TemplateFlow template IDs (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}`` would lead to resampling on a 2mm resolution of the space). name : :obj:`str` Name of workflow (default: ``bold_std_trans_wf``) use_compression : :obj:`bool` Save registered BOLD series as ``.nii.gz`` use_fieldwarp : :obj:`bool` Include SDC warp in single-shot transform from BOLD to MNI Inputs ------ anat2std_xfm List of anatomical-to-standard space transforms generated during spatial normalization. bold_aparc FreeSurfer's ``aparc+aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_aseg FreeSurfer's ``aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_mask Skull-stripping mask of reference image bold_split Individual 3D volumes, not motion corrected fieldwarp a :abbr:`DFM (displacements field map)` in ITK format hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format itk_bold_to_t1 Affine transform from ``ref_bold_brain`` to T1 space (ITK format) name_source BOLD series NIfTI file Used to recover original information lost during processing templates List of templates that were applied as targets during spatial normalization. Outputs ------- bold_std BOLD series, resampled to template space bold_std_ref Reference, contrast-enhanced summary of the BOLD series, resampled to template space bold_mask_std BOLD series mask in template space bold_aseg_std FreeSurfer's ``aseg.mgz`` atlas, in template space at the BOLD resolution (only if ``recon-all`` was run) bold_aparc_std FreeSurfer's ``aparc+aseg.mgz`` atlas, in template space at the BOLD resolution (only if ``recon-all`` was run) template Template identifiers synchronized correspondingly to previously described outputs. """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.func.util import init_bold_reference_wf from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.utility import KeySelect from niworkflows.interfaces.utils import GenerateSamplingReference from niworkflows.interfaces.nilearn import Merge from niworkflows.utils.spaces import format_reference workflow = Workflow(name=name) output_references = spaces.cached.get_spaces(nonstandard=False, dim=(3, )) std_vol_references = [(s.fullname, s.spec) for s in spaces.references if s.standard and s.dim == 3] if len(output_references) == 1: workflow.__desc__ = """\ The BOLD time-series were resampled into standard space, generating a *preprocessed BOLD run in {tpl} space*. """.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)) 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') iterablesource = pe.Node(niu.IdentityInterface(fields=['std_target']), name='iterablesource') # Generate conversions for every template+spec at the input 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') 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) 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) # 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) nxforms = 3 + use_fieldwarp merge_xforms = pe.Node(niu.Merge(nxforms), name='merge_xforms', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([(inputnode, merge_xforms, [('hmc_xforms', 'in%d' % nxforms)])]) if use_fieldwarp: workflow.connect([(inputnode, merge_xforms, [('fieldwarp', 'in3')])]) 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) 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) 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, [(('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')]), ]) 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') 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')]), ]) 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) 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')]), ]) # Connect parametric outputs to a Join outputnode outputnode = pe.JoinNode(niu.IdentityInterface(fields=output_names), name='outputnode', joinsource='iterablesource') workflow.connect([ (poutputnode, outputnode, [(f, f) for f in output_names]), ]) return workflow
def init_bold_t1_trans_wf(freesurfer, mem_gb, omp_nthreads, use_compression=True, name='bold_t1_trans_wf'): """ Co-register the reference BOLD image to T1w-space. The workflow uses :abbr:`BBR (boundary-based registration)`. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.registration import init_bold_t1_trans_wf wf = init_bold_t1_trans_wf(freesurfer=True, mem_gb=3, omp_nthreads=1) Parameters ---------- freesurfer : :obj:`bool` Enable FreeSurfer functional registration (bbregister) mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use use_compression : :obj:`bool` Save registered BOLD series as ``.nii.gz`` name : :obj:`str` Name of workflow (default: ``bold_reg_wf``) Inputs ------ name_source BOLD series NIfTI file Used to recover original information lost during processing ref_bold_brain Reference image to which BOLD series is aligned If ``fieldwarp == True``, ``ref_bold_brain`` should be unwarped ref_bold_mask Skull-stripping mask of reference image t1w_brain Skull-stripped bias-corrected structural template image t1w_mask Mask of the skull-stripped template image t1w_aseg FreeSurfer's ``aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). t1w_aparc FreeSurfer's ``aparc+aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_split Individual 3D BOLD volumes, not motion corrected hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format itk_bold_to_t1 Affine transform from ``ref_bold_brain`` to T1 space (ITK format) fieldwarp a :abbr:`DFM (displacements field map)` in ITK format Outputs ------- bold_t1 Motion-corrected BOLD series in T1 space bold_t1_ref Reference, contrast-enhanced summary of the motion-corrected BOLD series in T1w space bold_mask_t1 BOLD mask in T1 space bold_aseg_t1 FreeSurfer's ``aseg.mgz`` atlas, in T1w-space at the BOLD resolution (only if ``recon-all`` was run). bold_aparc_t1 FreeSurfer's ``aparc+aseg.mgz`` atlas, in T1w-space at the BOLD resolution (only if ``recon-all`` was run). See also -------- * :py:func:`~fmriprep.workflows.bold.registration.init_bbreg_wf` * :py:func:`~fmriprep.workflows.bold.registration.init_fsl_bbr_wf` """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.func.util import init_bold_reference_wf from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.nilearn import Merge from niworkflows.interfaces.utils import GenerateSamplingReference workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'name_source', 'ref_bold_brain', 'ref_bold_mask', 't1w_brain', 't1w_mask', 't1w_aseg', 't1w_aparc', 'bold_split', 'fieldwarp', 'hmc_xforms', 'itk_bold_to_t1' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'bold_t1', 'bold_t1_ref', 'bold_mask_t1', 'bold_aseg_t1', 'bold_aparc_t1' ]), name='outputnode') gen_ref = pe.Node(GenerateSamplingReference(), name='gen_ref', mem_gb=0.3) # 256x256x256 * 64 / 8 ~ 150MB mask_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel'), name='mask_t1w_tfm', mem_gb=0.1) workflow.connect([ (inputnode, gen_ref, [('ref_bold_brain', 'moving_image'), ('t1w_brain', 'fixed_image'), ('t1w_mask', 'fov_mask')]), (inputnode, mask_t1w_tfm, [('ref_bold_mask', 'input_image')]), (gen_ref, mask_t1w_tfm, [('out_file', 'reference_image')]), (inputnode, mask_t1w_tfm, [('itk_bold_to_t1', 'transforms')]), (mask_t1w_tfm, outputnode, [('output_image', 'bold_mask_t1')]), ]) if freesurfer: # Resample aseg and aparc in T1w space (no transforms needed) aseg_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', transforms='identity'), name='aseg_t1w_tfm', mem_gb=0.1) aparc_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', transforms='identity'), name='aparc_t1w_tfm', mem_gb=0.1) workflow.connect([ (inputnode, aseg_t1w_tfm, [('t1w_aseg', 'input_image')]), (inputnode, aparc_t1w_tfm, [('t1w_aparc', 'input_image')]), (gen_ref, aseg_t1w_tfm, [('out_file', 'reference_image')]), (gen_ref, aparc_t1w_tfm, [('out_file', 'reference_image')]), (aseg_t1w_tfm, outputnode, [('output_image', 'bold_aseg_t1')]), (aparc_t1w_tfm, outputnode, [('output_image', 'bold_aparc_t1')]), ]) bold_to_t1w_transform = pe.Node(MultiApplyTransforms( interpolation="LanczosWindowedSinc", float=True, copy_dtype=True), name='bold_to_t1w_transform', mem_gb=mem_gb * 3 * omp_nthreads, n_procs=omp_nthreads) # merge 3D volumes into 4D timeseries merge = pe.Node(Merge(compress=use_compression), name='merge', mem_gb=mem_gb) # Generate a reference on the target T1w space gen_final_ref = init_bold_reference_wf(omp_nthreads, pre_mask=True) # Merge transforms placing the head motion correction last merge_xforms = pe.Node(niu.Merge(3), name='merge_xforms', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), ( inputnode, merge_xforms, [ ('hmc_xforms', 'in3'), # May be 'identity' if HMC already applied ('fieldwarp', 'in2'), # May be 'identity' if SDC already applied ('itk_bold_to_t1', 'in1') ]), (inputnode, bold_to_t1w_transform, [('bold_split', 'input_image')]), (merge_xforms, bold_to_t1w_transform, [('out', 'transforms')]), (gen_ref, bold_to_t1w_transform, [('out_file', 'reference_image')]), (bold_to_t1w_transform, merge, [('out_files', 'in_files')]), (merge, gen_final_ref, [('out_file', 'inputnode.bold_file')]), (mask_t1w_tfm, gen_final_ref, [('output_image', 'inputnode.bold_mask') ]), (merge, outputnode, [('out_file', 'bold_t1')]), (gen_final_ref, outputnode, [('outputnode.ref_image', 'bold_t1_ref')]), ]) return workflow
def init_bold_t1_trans_wf(freesurfer, mem_gb, omp_nthreads, multiecho=False, use_fieldwarp=False, use_compression=True, name='bold_t1_trans_wf'): """ This workflow registers the reference BOLD image to T1-space, using a boundary-based registration (BBR) cost function. .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.registration import init_bold_t1_trans_wf wf = init_bold_t1_trans_wf(freesurfer=True, mem_gb=3, omp_nthreads=1) **Parameters** freesurfer : bool Enable FreeSurfer functional registration (bbregister) use_fieldwarp : bool Include SDC warp in single-shot transform from BOLD to T1 multiecho : bool If multiecho data was supplied, HMC already performed mem_gb : float Size of BOLD file in GB omp_nthreads : int Maximum number of threads an individual process may use use_compression : bool Save registered BOLD series as ``.nii.gz`` name : str Name of workflow (default: ``bold_reg_wf``) **Inputs** name_source BOLD series NIfTI file Used to recover original information lost during processing ref_bold_brain Reference image to which BOLD series is aligned If ``fieldwarp == True``, ``ref_bold_brain`` should be unwarped ref_bold_mask Skull-stripping mask of reference image t1_brain Skull-stripped bias-corrected structural template image t1_mask Mask of the skull-stripped template image t1_aseg FreeSurfer's ``aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). t1_aparc FreeSurfer's ``aparc+aseg.mgz`` atlas projected into the T1w reference (only if ``recon-all`` was run). bold_split Individual 3D BOLD volumes, not motion corrected hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format itk_bold_to_t1 Affine transform from ``ref_bold_brain`` to T1 space (ITK format) fieldwarp a :abbr:`DFM (displacements field map)` in ITK format **Outputs** bold_t1 Motion-corrected BOLD series in T1 space bold_t1_ref Reference, contrast-enhanced summary of the motion-corrected BOLD series in T1w space bold_mask_t1 BOLD mask in T1 space bold_aseg_t1 FreeSurfer's ``aseg.mgz`` atlas, in T1w-space at the BOLD resolution (only if ``recon-all`` was run). bold_aparc_t1 FreeSurfer's ``aparc+aseg.mgz`` atlas, in T1w-space at the BOLD resolution (only if ``recon-all`` was run). **Subworkflows** * :py:func:`~fmriprep.workflows.bold.registration.init_bbreg_wf` * :py:func:`~fmriprep.workflows.bold.registration.init_fsl_bbr_wf` """ from .util import init_bold_reference_wf workflow = Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'name_source', 'ref_bold_brain', 'ref_bold_mask', 't1_brain', 't1_mask', 't1_aseg', 't1_aparc', 'bold_split', 'fieldwarp', 'hmc_xforms', 'itk_bold_to_t1' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'bold_t1', 'bold_t1_ref', 'bold_mask_t1', 'bold_aseg_t1', 'bold_aparc_t1' ]), name='outputnode') gen_ref = pe.Node(GenerateSamplingReference(), name='gen_ref', mem_gb=0.3) # 256x256x256 * 64 / 8 ~ 150MB mask_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', float=True), name='mask_t1w_tfm', mem_gb=0.1) workflow.connect([ (inputnode, gen_ref, [('ref_bold_brain', 'moving_image'), ('t1_brain', 'fixed_image'), ('t1_mask', 'fov_mask')]), (inputnode, mask_t1w_tfm, [('ref_bold_mask', 'input_image')]), (gen_ref, mask_t1w_tfm, [('out_file', 'reference_image')]), (inputnode, mask_t1w_tfm, [('itk_bold_to_t1', 'transforms')]), (mask_t1w_tfm, outputnode, [('output_image', 'bold_mask_t1')]), ]) if freesurfer: # Resample aseg and aparc in T1w space (no transforms needed) aseg_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', transforms='identity', float=True), name='aseg_t1w_tfm', mem_gb=0.1) aparc_t1w_tfm = pe.Node(ApplyTransforms(interpolation='MultiLabel', transforms='identity', float=True), name='aparc_t1w_tfm', mem_gb=0.1) workflow.connect([ (inputnode, aseg_t1w_tfm, [('t1_aseg', 'input_image')]), (inputnode, aparc_t1w_tfm, [('t1_aparc', 'input_image')]), (gen_ref, aseg_t1w_tfm, [('out_file', 'reference_image')]), (gen_ref, aparc_t1w_tfm, [('out_file', 'reference_image')]), (aseg_t1w_tfm, outputnode, [('output_image', 'bold_aseg_t1')]), (aparc_t1w_tfm, outputnode, [('output_image', 'bold_aparc_t1')]), ]) bold_to_t1w_transform = pe.Node(MultiApplyTransforms( interpolation="LanczosWindowedSinc", float=True, copy_dtype=True), name='bold_to_t1w_transform', mem_gb=mem_gb * 3 * omp_nthreads, n_procs=omp_nthreads) # merge 3D volumes into 4D timeseries merge = pe.Node(Merge(compress=use_compression), name='merge', mem_gb=mem_gb) # Generate a reference on the target T1w space gen_final_ref = init_bold_reference_wf(omp_nthreads, pre_mask=True) if not multiecho: # Merge transforms placing the head motion correction last nforms = 2 + int(use_fieldwarp) merge_xforms = pe.Node(niu.Merge(nforms), name='merge_xforms', run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB) if use_fieldwarp: workflow.connect([(inputnode, merge_xforms, [('fieldwarp', 'in2')]) ]) workflow.connect([ # merge transforms (inputnode, merge_xforms, [('hmc_xforms', 'in%d' % nforms), ('itk_bold_to_t1', 'in1')]), (merge_xforms, bold_to_t1w_transform, [('out', 'transforms')]), (inputnode, bold_to_t1w_transform, [('bold_split', 'input_image') ]), ]) else: from nipype.interfaces.fsl import Split as FSLSplit bold_split = pe.Node(FSLSplit(dimension='t'), name='bold_split', mem_gb=DEFAULT_MEMORY_MIN_GB) workflow.connect([ (inputnode, bold_split, [('bold_split', 'in_file')]), (bold_split, bold_to_t1w_transform, [('out_files', 'input_image') ]), (inputnode, bold_to_t1w_transform, [('itk_bold_to_t1', 'transforms')]), ]) workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), (gen_ref, bold_to_t1w_transform, [('out_file', 'reference_image')]), (bold_to_t1w_transform, merge, [('out_files', 'in_files')]), (merge, gen_final_ref, [('out_file', 'inputnode.bold_file')]), (mask_t1w_tfm, gen_final_ref, [('output_image', 'inputnode.bold_mask') ]), (merge, outputnode, [('out_file', 'bold_t1')]), (gen_final_ref, outputnode, [('outputnode.ref_image', 'bold_t1_ref')]), ]) return workflow
def init_bold_preproc_trans_wf( mem_gb, omp_nthreads, name="bold_preproc_trans_wf", use_compression=True, use_fieldwarp=False, split_file=False, interpolation="LanczosWindowedSinc", ): """ Resample in native (original) space. This workflow resamples the input fMRI in its native (original) space in a "single shot" from the original BOLD series. Workflow Graph .. workflow:: :graph2use: colored :simple_form: yes from fprodents.workflows.bold.resampling import init_bold_preproc_trans_wf wf = init_bold_preproc_trans_wf(mem_gb=3, omp_nthreads=1) Parameters ---------- mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use name : :obj:`str` Name of workflow (default: ``bold_std_trans_wf``) use_compression : :obj:`bool` Save registered BOLD series as ``.nii.gz`` use_fieldwarp : :obj:`bool` Include SDC warp in single-shot transform from BOLD to MNI split_file : :obj:`bool` Whether the input file should be splitted (it is a 4D file) or it is a list of 3D files (default ``False``, do not split) interpolation : :obj:`str` Interpolation type to be used by ANTs' ``applyTransforms`` (default ``'LanczosWindowedSinc'``) Inputs ------ bold_file Individual 3D volumes, not motion corrected bold_mask Skull-stripping mask of reference image bold_ref BOLD reference image: an average-like 3D image of the time-series name_source BOLD series NIfTI file Used to recover original information lost during processing hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format fieldwarp a :abbr:`DFM (displacements field map)` in ITK format Outputs ------- bold BOLD series, resampled in native space, including all preprocessing """ from bids.utils import listify from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.nilearn import Merge workflow = Workflow(name=name) workflow.__desc__ = """\ The BOLD time-series (including slice-timing correction when applied) were resampled onto their original, native space by applying {transforms}. These resampled BOLD time-series will be referred to as *preprocessed BOLD in original space*, or just *preprocessed BOLD*. """.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""") inputnode = pe.Node( niu.IdentityInterface(fields=[ "name_source", "bold_file", "bold_mask", "bold_ref", "hmc_xforms", "fieldwarp" ]), name="inputnode", ) outputnode = pe.Node(niu.IdentityInterface(fields=["bold"]), name="outputnode") bold_transform = pe.Node( MultiApplyTransforms(interpolation=interpolation, float=True, copy_dtype=True), 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) # fmt:off workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), (bold_transform, merge, [('out_files', 'in_files')]), (inputnode, bold_transform, [(('hmc_xforms', listify), 'transforms'), ('bold_ref', 'reference_image')]), (merge, outputnode, [('out_file', 'bold')]), ]) # fmt:on # Input file is not splitted if split_file: bold_split = pe.Node(FSLSplit(dimension="t"), name="bold_split", mem_gb=mem_gb * 3) # fmt:off workflow.connect([(inputnode, bold_split, [('bold_file', 'in_file')]), (bold_split, bold_transform, [('out_files', 'input_image')])]) # fmt:on else: # fmt:off workflow.connect([ (inputnode, bold_transform, [('bold_file', 'input_image')]), ]) # fmt:on return workflow
def init_apply_hmc_only_wf(mem_gb, omp_nthreads, name='apply_hmc_only', use_compression=True, split_file=False, interpolation='LanczosWindowedSinc'): """ Resample in native (original) space. This workflow resamples the input fMRI in its native (original) space in a "single shot" from the original BOLD series. Parameters ---------- mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use name : :obj:`str` Name of workflow (default: ``bold_std_trans_wf``) split_file : :obj:`bool` Whether the input file should be splitted (it is a 4D file) or it is a list of 3D files (default ``False``, do not split) interpolation : :obj:`str` Interpolation type to be used by ANTs' ``applyTransforms`` (default ``'LanczosWindowedSinc'``) Inputs ------ bold_file Individual 3D volumes, not motion corrected name_source BOLD series NIfTI file Used to recover original information lost during processing hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format Outputs ------- bold BOLD series, resampled in native space, including all preprocessing """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.func.util import init_bold_reference_wf from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.nilearn import Merge from nipype.interfaces.fsl import Split as FSLSplit workflow = Workflow(name=name) workflow.__desc__ = """\ The BOLD time-series (including slice-timing correction when applied) were resampled onto their original, native space by applying {transforms}. These resampled BOLD time-series will be referred to as *preprocessed BOLD in original space*, or just *preprocessed BOLD*. """.format(transforms="""\ the transforms to correct for head-motion""") inputnode = pe.Node(niu.IdentityInterface( fields=['name_source', 'bold_file', 'hmc_xforms']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['bold']), name='outputnode') bold_transform = pe.Node(MultiApplyTransforms(interpolation=interpolation, float=True, copy_dtype=True), 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) workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), (bold_transform, merge, [('out_files', 'in_files')]), (merge, outputnode, [('out_file', 'bold')]), ]) # Input file is not splitted if split_file: bold_split = pe.Node(FSLSplit(dimension='t'), name='bold_split', mem_gb=mem_gb * 3) workflow.connect([(inputnode, bold_split, [('bold_file', 'in_file')]), (bold_split, bold_transform, [ ('out_files', 'input_image'), (('out_files', _first), 'reference_image'), ])]) else: workflow.connect([ (inputnode, bold_transform, [('bold_file', 'input_image'), (('bold_file', _first), 'reference_image')]), ]) def _aslist(val): return [val] workflow.connect([ (inputnode, bold_transform, [(('hmc_xforms', _aslist), 'transforms')]), ]) 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'): """ Resample in native (original) space. This workflow resamples the input fMRI in its native (original) space in a "single shot" from the original BOLD series. Workflow Graph .. workflow:: :graph2use: colored :simple_form: yes from fmriprep.workflows.bold import init_bold_preproc_trans_wf wf = init_bold_preproc_trans_wf(mem_gb=3, omp_nthreads=1) Parameters ---------- mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use name : :obj:`str` Name of workflow (default: ``bold_std_trans_wf``) use_compression : :obj:`bool` Save registered BOLD series as ``.nii.gz`` use_fieldwarp : :obj:`bool` Include SDC warp in single-shot transform from BOLD to MNI interpolation : :obj:`str` Interpolation type to be used by ANTs' ``applyTransforms`` (default ``'LanczosWindowedSinc'``) Inputs ------ bold_file Individual 3D volumes, not motion corrected name_source BOLD series NIfTI file Used to recover original information lost during processing hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format fieldwarp a :abbr:`DFM (displacements field map)` in ITK format Outputs ------- bold BOLD series, resampled in native space, including all preprocessing """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.nilearn import Merge workflow = Workflow(name=name) workflow.__desc__ = """\ The BOLD time-series (including slice-timing correction when applied) were resampled onto their original, native space by applying {transforms}. These resampled BOLD time-series will be referred to as *preprocessed BOLD in original space*, or just *preprocessed BOLD*. """.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""") inputnode = pe.Node(niu.IdentityInterface( fields=['name_source', 'bold_file', 'hmc_xforms', 'fieldwarp']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['bold']), name='outputnode') 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, float=True, copy_dtype=True), 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) 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')]), ]) return workflow
def init_bold_t1_trans_wf( mem_gb, omp_nthreads, multiecho=False, use_fieldwarp=False, use_compression=True, name="bold_t1_trans_wf", ): """ Co-register the reference BOLD image to T1w-space. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from fprodents.workflows.bold.registration import init_bold_t1_trans_wf wf = init_bold_t1_trans_wf(mem_gb=3, omp_nthreads=1) Parameters ---------- use_fieldwarp : :obj:`bool` Include SDC warp in single-shot transform from BOLD to T1 multiecho : :obj:`bool` If multiecho data was supplied, HMC already performed mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use use_compression : :obj:`bool` Save registered BOLD series as ``.nii.gz`` name : :obj:`str` Name of workflow (default: ``bold_reg_wf``) Inputs ------ name_source BOLD series NIfTI file Used to recover original information lost during processing ref_bold_brain Reference image to which BOLD series is aligned If ``fieldwarp == True``, ``ref_bold_brain`` should be unwarped t1w_brain Skull-stripped bias-corrected structural template image t1w_mask Mask of the skull-stripped template image bold_split Individual 3D BOLD volumes, not motion corrected hmc_xforms List of affine transforms aligning each volume to ``ref_image`` in ITK format bold2anat Affine transform from ``ref_bold_brain`` to T1 space (ITK format) fieldwarp a :abbr:`DFM (displacements field map)` in ITK format Outputs ------- bold_t1 Motion-corrected BOLD series in T1 space bold_t1_ref Reference, contrast-enhanced summary of the motion-corrected BOLD series in T1w space """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms from niworkflows.interfaces.itk import MultiApplyTransforms from niworkflows.interfaces.nibabel import GenerateSamplingReference from niworkflows.interfaces.nilearn import Merge workflow = Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=[ "name_source", "ref_bold_brain", "t1w_brain", "t1w_mask", "bold_split", "fieldwarp", "hmc_xforms", "bold2anat", ]), name="inputnode", ) outputnode = pe.Node( niu.IdentityInterface( fields=["bold_t1", "bold_t1_ref", "bold_mask_t1"]), name="outputnode", ) gen_ref = pe.Node(GenerateSamplingReference(), name="gen_ref", mem_gb=0.3) # 256x256x256 * 64 / 8 ~ 150MB bold_ref_t1w_tfm = pe.Node( ApplyTransforms(interpolation="LanczosWindowedSinc"), name="bold_ref_t1w_tfm", mem_gb=0.1) # fmt:off workflow.connect([ (inputnode, gen_ref, [('ref_bold_brain', 'moving_image'), ('t1w_brain', 'fixed_image'), ('t1w_mask', 'fov_mask')]), (inputnode, bold_ref_t1w_tfm, [('ref_bold_brain', 'input_image')]), (gen_ref, bold_ref_t1w_tfm, [('out_file', 'reference_image')]), (inputnode, bold_ref_t1w_tfm, [('bold2anat', 'transforms')]), (bold_ref_t1w_tfm, outputnode, [('output_image', 'bold_t1_ref')]), ]) # fmt:on bold_to_t1w_transform = pe.Node( MultiApplyTransforms(interpolation="LanczosWindowedSinc", float=True, copy_dtype=True), name="bold_to_t1w_transform", mem_gb=mem_gb * 3 * omp_nthreads, n_procs=omp_nthreads, ) # merge 3D volumes into 4D timeseries merge = pe.Node(Merge(compress=use_compression), name="merge", mem_gb=mem_gb) if not multiecho: # Merge transforms placing the head motion correction last nforms = 2 + int(use_fieldwarp) merge_xforms = pe.Node( niu.Merge(nforms), name="merge_xforms", run_without_submitting=True, mem_gb=DEFAULT_MEMORY_MIN_GB, ) if use_fieldwarp: # fmt:off workflow.connect([(inputnode, merge_xforms, [('fieldwarp', 'in2')]) ]) # fmt:on # fmt:off workflow.connect([ # merge transforms (inputnode, merge_xforms, [('hmc_xforms', 'in%d' % nforms), ('bold2anat', 'in1')]), (merge_xforms, bold_to_t1w_transform, [('out', 'transforms')]), (inputnode, bold_to_t1w_transform, [('bold_split', 'input_image') ]), ]) # fmt:on else: from nipype.interfaces.fsl import Split as FSLSplit bold_split = pe.Node(FSLSplit(dimension="t"), name="bold_split", mem_gb=DEFAULT_MEMORY_MIN_GB) # fmt:off workflow.connect([ (inputnode, bold_split, [('bold_split', 'in_file')]), (bold_split, bold_to_t1w_transform, [('out_files', 'input_image') ]), (inputnode, bold_to_t1w_transform, [('bold2anat', 'transforms')]), ]) # fmt:on # fmt:off workflow.connect([ (inputnode, merge, [('name_source', 'header_source')]), (gen_ref, bold_to_t1w_transform, [('out_file', 'reference_image')]), (bold_to_t1w_transform, merge, [('out_files', 'in_files')]), (merge, outputnode, [('out_file', 'bold_t1')]), ]) # fmt:on return workflow