예제 #1
0
def init_qwarp_inversion_wf(omp_nthreads=1, name="qwarp_invert_wf"):
    """
    Invert a warp produced by 3dqwarp and convert it to an ANTS formatted warp
    Workflow Graph
        .. workflow ::
            :graph2use: orig
            :simple_form: yes
            from sdcflows.workflows.base import init_qwarp_inversion_wf
            wf = init_qwarp_inversion_wf()
    Parameters
    ----------
    name : str
        Name for this workflow
    omp_nthreads : int
        Parallelize internal tasks across the number of CPUs given by this option.
    Inputs
    ------
    warp : pathlike
        The warp you want to invert.
    in_reference : pathlike
        The baseline reference image (must correspond to ``epi_pe_dir``).
    Outputs
    -------
    out_warp : pathlike
        The corresponding inverted :abbr:`DFM (displacements field map)` compatible with
        ANTs.
    """
    from ..interfaces.afni import InvertWarp
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A warp produced by 3dQwarp was inverted by `3dNwarpCat` @afni (AFNI {afni_ver}).
""".format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []]))

    inputnode = pe.Node(niu.IdentityInterface(fields=['warp', 'in_reference']),
                        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(fields=['out_warp']),
                         name='outputnode')

    invert = pe.Node(InvertWarp(), name='invert', n_procs=omp_nthreads)
    invert.inputs.outputtype = 'NIFTI_GZ'
    to_ants = pe.Node(niu.Function(function=_fix_hdr),
                      name='to_ants',
                      mem_gb=0.01)

    cphdr_warp = pe.Node(CopyHeader(), name='cphdr_warp', mem_gb=0.01)

    workflow.connect([
        (inputnode, invert, [('warp', 'in_file')]),
        (invert, cphdr_warp, [('out_file', 'in_file')]),
        (inputnode, cphdr_warp, [('in_reference', 'hdr_file')]),
        (cphdr_warp, to_ants, [('out_file', 'in_file')]),
        (to_ants, outputnode, [('out', 'out_warp')]),
    ])

    return workflow
예제 #2
0
def init_pepolar_unwarp_wf(omp_nthreads=1,
                           matched_pe=False,
                           name="pepolar_unwarp_wf"):
    """
    Create the PE-Polar field estimation workflow.

    This workflow takes in a set of EPI files with opposite phase encoding
    direction than the target file and calculates a displacements field
    (in other words, an ANTs-compatible warp file).

    This procedure works if there is only one '_epi' file is present
    (as long as it has the opposite phase encoding direction to the target
    file). The target file will be used to estimate the field distortion.
    However, if there is another '_epi' file present with a matching
    phase encoding direction to the target it will be used instead.

    Currently, different phase encoding dimension in the target file and the
    '_epi' file(s) (for example 'i' and 'j') is not supported.

    The warp field correcting for the distortions is estimated using AFNI's
    3dQwarp, with displacement estimation limited to the target file phase
    encoding direction.

    It also calculates a new mask for the input dataset that takes into
    account the distortions.

    .. workflow ::
        :graph2use: orig
        :simple_form: yes

        from sdcflows.workflows.pepolar import init_pepolar_unwarp_wf
        wf = init_pepolar_unwarp_wf()


    **Parameters**:

        matched_pe : bool
            Whether the input ``fmaps_epi`` will contain images with matched
            PE blips or not. Please use :func:`sdcflows.workflows.pepolar.check_pes`
            to determine whether they exist or not.
        name : str
            Name for this workflow
        omp_nthreads : int
            Parallelize internal tasks across the number of CPUs given by this option.

    **Inputs**:

        fmaps_epi : list of tuple(pathlike, str)
            The list of EPI images that will be used in PE-Polar correction, and
            their corresponding ``PhaseEncodingDirection`` metadata.
            The workflow will use the ``bold_pe_dir`` input to separate out those
            EPI acquisitions with opposed PE blips and those with matched PE blips
            (the latter could be none, and ``in_reference_brain`` would then be
            used). The workflow raises a ``ValueError`` when no images with
            opposed PE blips are found.
        bold_pe_dir : str
            The baseline PE direction.
        in_reference : pathlike
            The baseline reference image (must correspond to ``bold_pe_dir``).
        in_reference_brain : pathlike
            The reference image above, but skullstripped.
        in_mask : pathlike
            Not used, present only for consistency across fieldmap estimation
            workflows.


    **Outputs**:

        out_reference : pathlike
            The ``in_reference`` after unwarping
        out_reference_brain : pathlike
            The ``in_reference`` after unwarping and skullstripping
        out_warp : pathlike
            The corresponding :abbr:`DFM (displacements field map)` compatible with
            ANTs.
        out_mask : pathlike
            Mask of the unwarped input file

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A deformation field to correct for susceptibility distortions was estimated
based on two echo-planar imaging (EPI) references with opposing phase-encoding
directions, using `3dQwarp` @afni (AFNI {afni_ver}).
""".format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []]))

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'fmaps_epi', 'in_reference', 'in_reference_brain', 'in_mask',
        'bold_pe_dir'
    ]),
                        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(fields=[
        'out_reference', 'out_reference_brain', 'out_warp', 'out_mask'
    ]),
                         name='outputnode')

    prepare_epi_wf = init_prepare_epi_wf(omp_nthreads=omp_nthreads,
                                         matched_pe=matched_pe,
                                         name="prepare_epi_wf")

    qwarp = pe.Node(afni.QwarpPlusMinus(
        pblur=[0.05, 0.05],
        blur=[-1, -1],
        noweight=True,
        minpatch=9,
        nopadWARP=True,
        environ={'OMP_NUM_THREADS': '%d' % omp_nthreads}),
                    name='qwarp',
                    n_procs=omp_nthreads)

    to_ants = pe.Node(niu.Function(function=_fix_hdr),
                      name='to_ants',
                      mem_gb=0.01)

    cphdr_warp = pe.Node(CopyHeader(), name='cphdr_warp', mem_gb=0.01)

    unwarp_reference = pe.Node(ANTSApplyTransformsRPT(
        dimension=3,
        generate_report=False,
        float=True,
        interpolation='LanczosWindowedSinc'),
                               name='unwarp_reference')

    enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf(
        omp_nthreads=omp_nthreads)

    workflow.connect([
        (inputnode, qwarp, [(('bold_pe_dir', _qwarp_args), 'args')]),
        (inputnode, cphdr_warp, [('in_reference', 'hdr_file')]),
        (inputnode, prepare_epi_wf, [('fmaps_epi', 'inputnode.maps_pe'),
                                     ('bold_pe_dir', 'inputnode.epi_pe'),
                                     ('in_reference_brain',
                                      'inputnode.ref_brain')]),
        (prepare_epi_wf, qwarp, [('outputnode.opposed_pe', 'base_file'),
                                 ('outputnode.matched_pe', 'in_file')]),
        (qwarp, cphdr_warp, [('source_warp', 'in_file')]),
        (cphdr_warp, to_ants, [('out_file', 'in_file')]),
        (to_ants, unwarp_reference, [('out', 'transforms')]),
        (inputnode, unwarp_reference, [('in_reference', 'reference_image'),
                                       ('in_reference', 'input_image')]),
        (unwarp_reference, enhance_and_skullstrip_bold_wf,
         [('output_image', 'inputnode.in_file')]),
        (unwarp_reference, outputnode, [('output_image', 'out_reference')]),
        (enhance_and_skullstrip_bold_wf, outputnode,
         [('outputnode.mask_file', 'out_mask'),
          ('outputnode.skull_stripped_file', 'out_reference_brain')]),
        (to_ants, outputnode, [('out', 'out_warp')]),
    ])

    return workflow
예제 #3
0
def init_pepolar_unwarp_wf(dwi_meta,
                           epi_fmaps,
                           omp_nthreads=1,
                           name="pepolar_unwarp_wf"):
    """
    This workflow takes in a set of EPI files with opposite phase encoding
    direction than the target file and calculates a displacements field
    (in other words, an ANTs-compatible warp file).

    This procedure works if there is only one '_epi' file is present
    (as long as it has the opposite phase encoding direction to the target
    file). The target file will be used to estimate the field distortion.
    However, if there is another '_epi' file present with a matching
    phase encoding direction to the target it will be used instead.

    Currently, different phase encoding dimension in the target file and the
    '_epi' file(s) (for example 'i' and 'j') is not supported.

    The warp field correcting for the distortions is estimated using AFNI's
    3dQwarp, with displacement estimation limited to the target file phase
    encoding direction.

    It also calculates a new mask for the input dataset that takes into
    account the distortions.

    .. workflow ::
        :graph2use: orig
        :simple_form: yes

        from qsiprep.workflows.fieldmap.pepolar import init_pepolar_unwarp_wf
        wf = init_pepolar_unwarp_wf(
            dwi_meta={'PhaseEncodingDirection': 'j'},
            epi_fmaps=[('/dataset/sub-01/fmap/sub-01_epi.nii.gz', 'j-')],
            omp_nthreads=8)


    Inputs

        in_reference
            the reference image
        in_reference_brain
            the reference image skullstripped
        in_mask
            a brain mask corresponding to ``in_reference``

    Outputs

        out_reference
            the ``in_reference`` after unwarping
        out_warp
            the corresponding :abbr:`DFM (displacements field map)` compatible with
            ANTs

    """
    dwi_file_pe = dwi_meta["PhaseEncodingDirection"]

    args = '-noXdis -noYdis -noZdis'
    rm_arg = {'i': '-noXdis', 'j': '-noYdis', 'k': '-noZdis'}[dwi_file_pe[0]]
    args = args.replace(rm_arg, '')

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A deformation field to correct for susceptibility distortions was estimated
based on two echo-planar imaging (EPI) references with opposing phase-encoding
directions, using `3dQwarp` @afni (AFNI {afni_ver}).
""".format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []]))

    inputnode = pe.Node(niu.IdentityInterface(
        fields=['in_reference', 'in_reference_brain', 'in_mask']),
                        name='inputnode')

    outputnode = pe.Node(
        niu.IdentityInterface(fields=['out_reference', 'out_warp']),
        name='outputnode')

    prepare_epi_opposite_wf = init_prepare_dwi_epi_wf(
        omp_nthreads=omp_nthreads, name="prepare_epi_opposite_wf")
    prepare_epi_opposite_wf.inputs.inputnode.fmaps = epi_fmaps

    qwarp = pe.Node(afni.QwarpPlusMinus(
        pblur=[0.05, 0.05],
        blur=[-1, -1],
        noweight=True,
        minpatch=9,
        nopadWARP=True,
        environ={'OMP_NUM_THREADS': '%d' % omp_nthreads},
        args=args),
                    name='qwarp',
                    n_procs=omp_nthreads)

    workflow.connect([(inputnode, prepare_epi_opposite_wf,
                       [('in_reference_brain', 'inputnode.ref_brain')]),
                      (prepare_epi_opposite_wf, qwarp, [('outputnode.out_file',
                                                         'base_file')]),
                      (inputnode, qwarp, [('in_reference_brain', 'in_file')])])

    to_ants = pe.Node(niu.Function(function=_fix_hdr),
                      name='to_ants',
                      mem_gb=0.01)

    cphdr_warp = pe.Node(CopyHeader(), name='cphdr_warp', mem_gb=0.01)

    unwarp_reference = pe.Node(ANTSApplyTransformsRPT(
        dimension=3,
        generate_report=False,
        float=True,
        interpolation='LanczosWindowedSinc'),
                               name='unwarp_reference')

    workflow.connect([
        (inputnode, cphdr_warp, [('in_reference', 'hdr_file')]),
        (qwarp, cphdr_warp, [('source_warp', 'in_file')]),
        (cphdr_warp, to_ants, [('out_file', 'in_file')]),
        (to_ants, unwarp_reference, [('out', 'transforms')]),
        (inputnode, unwarp_reference, [('in_reference', 'reference_image'),
                                       ('in_reference', 'input_image')]),
        (unwarp_reference, outputnode, [('output_image', 'out_reference')]),
        (to_ants, outputnode, [('out', 'out_warp')]),
    ])

    return workflow
예제 #4
0
def init_bold_stc_wf(metadata, name='bold_stc_wf'):
    """
    Create a workflow for :abbr:`STC (slice-timing correction)`.

    This workflow performs :abbr:`STC (slice-timing correction)` over the input
    :abbr:`BOLD (blood-oxygen-level dependent)` image.

    Workflow Graph
        .. workflow::
            :graph2use: orig
            :simple_form: yes

            from fmriprep.workflows.bold import init_bold_stc_wf
            wf = init_bold_stc_wf(
                metadata={"RepetitionTime": 2.0,
                          "SliceTiming": [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]},
                )

    Parameters
    ----------
    metadata : :obj:`dict`
        BIDS metadata for BOLD file
    name : :obj:`str`
        Name of workflow (default: ``bold_stc_wf``)

    Inputs
    ------
    bold_file
        BOLD series NIfTI file
    skip_vols
        Number of non-steady-state volumes detected at beginning of ``bold_file``

    Outputs
    -------
    stc_file
        Slice-timing corrected BOLD series NIfTI file

    """
    from niworkflows.engine.workflows import LiterateWorkflow as Workflow
    from niworkflows.interfaces.utils import CopyXForm

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
BOLD runs were slice-time corrected using `3dTshift` from
AFNI {afni_ver} [@afni, RRID:SCR_005927].
""".format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []]))
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['bold_file', 'skip_vols']),
        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']),
                         name='outputnode')

    LOGGER.log(25, 'Slice-timing correction will be included.')

    # It would be good to fingerprint memory use of afni.TShift
    slice_timing_correction = pe.Node(afni.TShift(
        outputtype='NIFTI_GZ',
        tr='{}s'.format(metadata["RepetitionTime"]),
        slice_timing=metadata['SliceTiming'],
        slice_encoding_direction=metadata.get('SliceEncodingDirection', 'k')),
                                      name='slice_timing_correction')

    copy_xform = pe.Node(CopyXForm(), name='copy_xform', mem_gb=0.1)

    workflow.connect([
        (inputnode, slice_timing_correction, [('bold_file', 'in_file'),
                                              ('skip_vols', 'ignore')]),
        (slice_timing_correction, copy_xform, [('out_file', 'in_file')]),
        (inputnode, copy_xform, [('bold_file', 'hdr_file')]),
        (copy_xform, outputnode, [('out_file', 'stc_file')]),
    ])

    return workflow
예제 #5
0
def init_bidirectional_b0_unwarping_wf(template_plus_pe, omp_nthreads=1,
                                       name="bidirectional_pepolar_unwarping_wf"):
    """
    This workflow takes in a set of b0 files with opposite phase encoding
    direction and calculates displacement fields
    (in other words, an ANTs-compatible warp file). This is intended to be run
    in the case where there are two dwi series in the same session with reverse
    phase encoding directions.

    The warp field correcting for the distortions is estimated using AFNI's
    3dQwarp, with displacement estimation limited to the target file phase
    encoding direction.

    It also calculates a new mask for the input dataset that takes into
    account the distortions.

    .. workflow ::
        :graph2use: orig
        :simple_form: yes

        from qsiprep.workflows.fieldmap.pepolar import init_pepolar_unwarp_wf
        wf = init_pepolar_unwarp_wf(
            bold_meta={'PhaseEncodingDirection': 'j'},
            epi_fmaps=[('/dataset/sub-01/fmap/sub-01_epi.nii.gz', 'j-')],
            omp_nthreads=8)


    Inputs

        template_plus
            b0 template in one PE
        template_minus
            b0_template in the other PE

    Outputs

        out_reference
            the ``in_reference`` after unwarping
        out_reference_brain
            the ``in_reference`` after unwarping and skullstripping
        out_warp_plus
            the corresponding :abbr:`DFM (displacements field map)` to correct
            ``template_plus``
        out_warp_minus
            the corresponding :abbr:`DFM (displacements field map)` to correct
            ``template_minus``
        out_mask
            mask of the unwarped input file

    """
    args = '-noXdis -noYdis -noZdis'
    rm_arg = {'i': '-noXdis',
              'j': '-noYdis',
              'k': '-noZdis'}[template_plus_pe[0]]
    args = args.replace(rm_arg, '')

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
A deformation field to correct for susceptibility distortions was estimated
based on two b0 templates created from dwi series with opposing phase-encoding
directions, using `3dQwarp` @afni (AFNI {afni_ver}).
""".format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []]))

    inputnode = pe.Node(niu.IdentityInterface(
        fields=['template_plus', 'template_minus', 't1w_brain']),
        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['out_reference', 'out_reference_brain', 'out_affine_plus', 'out_warp_plus',
                'out_affine_minus', 'out_warp_minus', 'out_mask']), name='outputnode')
    # Create high-contrast ref images
    plus_ref_wf = init_dwi_reference_wf(name='plus_ref_wf')
    minus_ref_wf = init_dwi_reference_wf(name='minus_ref_wf')

    # Align the two reference images to the midpoint
    inputs_to_list = pe.Node(niu.Merge(2), name='inputs_to_list')
    align_reverse_pe_wf = init_b0_hmc_wf(align_to='iterative', transform='Rigid')
    get_midpoint_transforms = pe.Node(niu.Split(splits=[1, 1], squeeze=True),
                                      name="get_midpoint_transforms")
    plus_to_midpoint = pe.Node(ants.ApplyTransforms(float=True,
                                                    interpolation='LanczosWindowedSinc',
                                                    dimension=3),
                               name='plus_to_midpoint')
    minus_to_midpoint = pe.Node(ants.ApplyTransforms(float=True,
                                                     interpolation='LanczosWindowedSinc',
                                                     dimension=3),
                                name='minus_to_midpoint')

    qwarp = pe.Node(afni.QwarpPlusMinus(pblur=[0.05, 0.05],
                                        blur=[-1, -1],
                                        noweight=True,
                                        minpatch=9,
                                        nopadWARP=True,
                                        environ={'OMP_NUM_THREADS': '%d' % omp_nthreads},
                                        args=args),
                    name='qwarp', n_procs=omp_nthreads)

    to_ants_plus = pe.Node(niu.Function(function=_fix_hdr), name='to_ants_plus',
                           mem_gb=0.01)
    to_ants_minus = pe.Node(niu.Function(function=_fix_hdr), name='to_ants_minus',
                            mem_gb=0.01)

    cphdr_plus_warp = pe.Node(CopyHeader(), name='cphdr_plus_warp', mem_gb=0.01)
    cphdr_minus_warp = pe.Node(CopyHeader(), name='cphdr_minus_warp', mem_gb=0.01)

    unwarp_plus_reference = pe.Node(ants.ApplyTransforms(dimension=3,
                                                         float=True,
                                                         interpolation='LanczosWindowedSinc'),
                                    name='unwarp_plus_reference')
    unwarp_minus_reference = pe.Node(ants.ApplyTransforms(dimension=3,
                                                          float=True,
                                                          interpolation='LanczosWindowedSinc'),
                                     name='unwarp_minus_reference')
    unwarped_to_list = pe.Node(niu.Merge(2), name="unwarped_to_list")
    merge_unwarped = pe.Node(ants.AverageImages(dimension=3, normalize=True),
                             name="merge_unwarped")

    final_ref = init_dwi_reference_wf(name="final_ref")

    workflow.connect([
        (inputnode, plus_ref_wf, [('template_plus', 'inputnode.b0_template')]),
        (plus_ref_wf, inputs_to_list, [('outputnode.ref_image', 'in1')]),
        (inputnode, minus_ref_wf, [('template_minus', 'inputnode.b0_template')]),
        (minus_ref_wf, inputs_to_list, [('outputnode.ref_image', 'in2')]),
        (inputs_to_list, align_reverse_pe_wf, [('out', 'inputnode.b0_images')]),
        (align_reverse_pe_wf, get_midpoint_transforms, [('outputnode.forward_transforms',
                                                         'inlist')]),
        (get_midpoint_transforms, outputnode, [('out1', 'out_affine_plus'),
                                               ('out2', 'out_affine_minus')]),
        (plus_ref_wf, plus_to_midpoint, [('outputnode.ref_image', 'input_image')]),
        (minus_ref_wf, minus_to_midpoint, [('outputnode.ref_image', 'input_image')]),
        (get_midpoint_transforms, plus_to_midpoint, [('out1', 'transforms')]),
        (align_reverse_pe_wf, plus_to_midpoint, [('outputnode.final_template',
                                                  'reference_image')]),
        (get_midpoint_transforms, minus_to_midpoint, [('out2', 'transforms')]),
        (align_reverse_pe_wf, minus_to_midpoint, [('outputnode.final_template',
                                                  'reference_image')]),
        (plus_to_midpoint, qwarp, [('output_image', 'in_file')]),
        (minus_to_midpoint, qwarp, [('output_image', 'base_file')]),
        (align_reverse_pe_wf, cphdr_plus_warp, [('outputnode.final_template', 'hdr_file')]),
        (align_reverse_pe_wf, cphdr_minus_warp, [('outputnode.final_template', 'hdr_file')]),
        (qwarp, cphdr_plus_warp, [('source_warp', 'in_file')]),
        (qwarp, cphdr_minus_warp, [('base_warp', 'in_file')]),
        (cphdr_plus_warp, to_ants_plus, [('out_file', 'in_file')]),
        (cphdr_minus_warp, to_ants_minus, [('out_file', 'in_file')]),

        (to_ants_minus, unwarp_minus_reference, [('out', 'transforms')]),
        (minus_to_midpoint, unwarp_minus_reference, [('output_image', 'reference_image'),
                                                     ('output_image', 'input_image')]),
        (to_ants_minus, outputnode, [('out', 'out_warp_minus')]),

        (to_ants_plus, unwarp_plus_reference, [('out', 'transforms')]),
        (plus_to_midpoint, unwarp_plus_reference, [('output_image', 'reference_image'),
                                                   ('output_image', 'input_image')]),
        (to_ants_plus, outputnode, [('out', 'out_warp_plus')]),

        (unwarp_plus_reference, unwarped_to_list, [('output_image', 'in1')]),
        (unwarp_minus_reference, unwarped_to_list, [('output_image', 'in2')]),
        (unwarped_to_list, merge_unwarped, [('out', 'images')]),

        (merge_unwarped, final_ref, [('output_average_image', 'inputnode.b0_template')]),
        (final_ref, outputnode, [('outputnode.ref_image', 'out_reference'),
                                 ('outputnode.ref_image_brain', 'out_reference_brain'),
                                 ('outputnode.dwi_mask', 'out_mask')])
    ])

    return workflow
예제 #6
0
def init_bold_hmc_wf(mem_gb, omp_nthreads, name="bold_hmc_wf"):
    """
    Build a workflow to estimate head-motion parameters.

    This workflow estimates the motion parameters to perform
    :abbr:`HMC (head motion correction)` over the input
    :abbr:`BOLD (blood-oxygen-level dependent)` image.

    Workflow Graph
        .. workflow::
            :graph2use: orig
            :simple_form: yes

            from fprodents.workflows.bold.hmc import init_bold_hmc_wf
            wf = init_bold_hmc_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_hmc_wf``)

    Inputs
    ------
    bold_file
        BOLD series NIfTI file
    raw_ref_image
        Reference image to which BOLD series is motion corrected

    Outputs
    -------
    xforms
        ITKTransform file aligning each volume to ``ref_image``
    movpar_file
        MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz)
    rms_file
        Framewise displacement as measured by ``fsl_motion_outliers`` [Jenkinson2002]_.

    """
    from niworkflows.engine.workflows import LiterateWorkflow as Workflow
    from niworkflows.interfaces.confounds import NormalizeMotionParams

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
Head-motion parameters with respect to the BOLD reference
(transformation matrices, and six corresponding rotation and translation
parameters) are estimated before any spatiotemporal filtering using
`3dVolReg` [AFNI {afni_ver}, @afni, RRID:SCR_005927].
""".format(afni_ver=afni.Info().version() or "<ver>")

    inputnode = pe.Node(
        niu.IdentityInterface(fields=["bold_file", "raw_ref_image"]),
        name="inputnode")
    outputnode = pe.Node(
        niu.IdentityInterface(fields=["xforms", "movpar_file", "rmsd_file"]),
        name="outputnode",
    )

    # Head motion correction (hmc)
    # mcflirt = pe.Node(
    #     fsl.MCFLIRT(save_mats=True, save_plots=True, save_rms=True),
    #     name='mcflirt', mem_gb=mem_gb * 3)

    # fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk',
    #                   mem_gb=0.05, n_procs=omp_nthreads)

    mc = pe.Node(
        afni.Volreg(zpad=4,
                    outputtype="NIFTI_GZ",
                    args="-prefix NULL -twopass"),
        name="mc",
        mem_gb=mem_gb * 3,
    )

    mc2itk = pe.Node(Volreg2ITK(), name="mcitk", mem_gb=0.05)

    normalize_motion = pe.Node(
        NormalizeMotionParams(format="AFNI"),
        name="normalize_motion",
        mem_gb=DEFAULT_MEMORY_MIN_GB,
    )

    # def _pick_rel(rms_files):
    #     return rms_files[-1]

    # workflow.connect([
    #     (inputnode, mcflirt, [('raw_ref_image', 'ref_file'),
    #                           ('bold_file', 'in_file')]),
    #     (inputnode, fsl2itk, [('raw_ref_image', 'in_source'),
    #                           ('raw_ref_image', 'in_reference')]),
    #     (mcflirt, fsl2itk, [('mat_file', 'in_files')]),
    #     (mcflirt, normalize_motion, [('par_file', 'in_file')]),
    #     (mcflirt, outputnode, [(('rms_files', _pick_rel), 'rmsd_file')]),
    #     (fsl2itk, outputnode, [('out_file', 'xforms')]),
    #     (normalize_motion, outputnode, [('out_file', 'movpar_file')]),
    # ])

    # fmt:off
    workflow.connect([
        (inputnode, mc, [
            ('raw_ref_image', 'basefile'),
            ('bold_file', 'in_file'),
        ]),
        (mc, mc2itk, [('oned_matrix_save', 'in_file')]),
        (mc, normalize_motion, [('oned_file', 'in_file')]),
        (mc2itk, outputnode, [('out_file', 'xforms')]),
        (normalize_motion, outputnode, [('out_file', 'movpar_file')]),
    ])
    # fmt:on

    return workflow