def test_ANTSRegistrationRPT(monkeypatch, reference, moving):
    """ the RobustMNINormalizationRPT report capable test """
    import pkg_resources as pkgr

    def _agg(objekt, runtime):
        outputs = objekt.output_spec()
        outputs.warped_image = os.path.join(
            datadir, "testANTSRegistrationRPT-warped_image.nii.gz")
        outputs.out_report = os.path.join(runtime.cwd,
                                          objekt.inputs.out_report)
        return outputs

    # Patch the _run_interface method
    monkeypatch.setattr(ANTSRegistrationRPT, "_run_interface",
                        _run_interface_mock)
    monkeypatch.setattr(ANTSRegistrationRPT, "aggregate_outputs", _agg)

    ants_rpt = ANTSRegistrationRPT(
        generate_report=True,
        moving_image=moving,
        fixed_image=reference,
        from_file=pkgr.resource_filename(
            "niworkflows.data", "t1w-mni_registration_testing_000.json"),
    )
    _smoke_test_report(ants_rpt, "testANTSRegistrationRPT.svg")
Example #2
0
 def test_ANTSRegistrationRPT(self):
     """ the RobustMNINormalizationRPT report capable test """
     ants_rpt = ANTSRegistrationRPT(
         generate_report=True,
         moving_image=self.moving,
         fixed_image=self.reference,
         from_file=pkgr.resource_filename(
             'niworkflows.data', 't1-mni_registration_testing_000.json'))
     _smoke_test_report(ants_rpt, 'testANTSRegistrationRPT.svg')
Example #3
0
def test_ANTSRegistrationRPT(monkeypatch, reference, moving):
    """ the RobustMNINormalizationRPT report capable test """
    import pkg_resources as pkgr

    def _agg(objekt, runtime):
        outputs = Bunch(warped_image=os.path.join(
            datadir, 'testANTSRegistrationRPT-warped_image.nii.gz'))
        return outputs

    # Patch the _run_interface method
    monkeypatch.setattr(ANTSRegistrationRPT, '_run_interface',
                        _run_interface_mock)
    monkeypatch.setattr(ANTSRegistrationRPT, 'aggregate_outputs', _agg)

    ants_rpt = ANTSRegistrationRPT(generate_report=True,
                                   moving_image=moving,
                                   fixed_image=reference,
                                   from_file=pkgr.resource_filename(
                                       'niworkflows.data',
                                       't1-mni_registration_testing_000.json'))
    _smoke_test_report(ants_rpt, 'testANTSRegistrationRPT.svg')
Example #4
0
def init_sdc_unwarp_wf(reportlets_dir,
                       omp_nthreads,
                       fmap_bspline,
                       fmap_demean,
                       debug,
                       name='sdc_unwarp_wf'):
    """
    This workflow takes in a displacements fieldmap and calculates the corresponding
    displacements field (in other words, an ANTs-compatible warp file).

    It also calculates a new mask for the input dataset that takes into account the distortions.
    The mask is restricted to the field of view of the fieldmap since outside of it corrections
    could not be performed.

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

        from fmriprep.workflows.fieldmap.unwarp import init_sdc_unwarp_wf
        wf = init_sdc_unwarp_wf(reportlets_dir='.', omp_nthreads=8,
                                fmap_bspline=False, fmap_demean=True,
                                debug=False)


    Inputs

        in_reference
            the reference image
        in_mask
            a brain mask corresponding to ``in_reference``
        name_source
            path to the original _bold file being unwarped
        fmap
            the fieldmap in Hz
        fmap_ref
            the reference (anatomical) image corresponding to ``fmap``
        fmap_mask
            a brain mask corresponding to ``fmap``


    Outputs

        out_reference
            the ``in_reference`` after unwarping
        out_reference_brain
            the ``in_reference`` after unwarping and skullstripping
        out_warp
            the corresponding :abbr:`DFM (displacements field map)` compatible with
            ANTs
        out_jacobian
            the jacobian of the field (for drop-out alleviation)
        out_mask
            mask of the unwarped input file
        out_mask_report
            reportled for the skullstripping

    """

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_reference', 'in_reference_brain', 'in_mask', 'name_source',
        'fmap_ref', 'fmap_mask', 'fmap'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=[
        'out_reference', 'out_reference_brain', 'out_warp', 'out_mask',
        'out_jacobian', 'out_mask_report'
    ]),
                         name='outputnode')

    meta = pe.Node(ReadSidecarJSON(), name='meta')

    # Register the reference of the fieldmap to the reference
    # of the target image (the one that shall be corrected)
    ants_settings = pkgr.resource_filename('fmriprep',
                                           'data/fmap-any_registration.json')
    if debug:
        ants_settings = pkgr.resource_filename(
            'fmriprep', 'data/fmap-any_registration_testing.json')
    fmap2ref_reg = pe.Node(ANTSRegistrationRPT(
        generate_report=True,
        from_file=ants_settings,
        output_inverse_warped_image=True,
        output_warped_image=True,
        num_threads=omp_nthreads),
                           name='fmap2ref_reg')
    fmap2ref_reg.interface.num_threads = omp_nthreads

    ds_reg = pe.Node(DerivativesDataSink(base_directory=reportlets_dir,
                                         suffix='fmap_reg'),
                     name='ds_reg')

    # Map the VSM into the EPI space
    fmap2ref_apply = pe.Node(ANTSApplyTransformsRPT(generate_report=True,
                                                    dimension=3,
                                                    interpolation='BSpline',
                                                    float=True),
                             name='fmap2ref_apply')

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

    ds_reg_vsm = pe.Node(DerivativesDataSink(base_directory=reportlets_dir,
                                             suffix='fmap_reg_vsm'),
                         name='ds_reg_vsm')

    # Fieldmap to rads and then to voxels (VSM - voxel shift map)
    torads = pe.Node(niu.Function(function=_hz2rads), name='torads')

    gen_vsm = pe.Node(fsl.FUGUE(save_unmasked_shift=True), name='gen_vsm')
    # Convert the VSM into a DFM (displacements field map)
    # or: FUGUE shift to ANTS warping.
    vsm2dfm = pe.Node(itk.FUGUEvsm2ANTSwarp(), name='vsm2dfm')
    jac_dfm = pe.Node(ants.CreateJacobianDeterminantImage(
        imageDimension=3, outputImage='jacobian.nii.gz'),
                      name='jac_dfm')

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

    fieldmap_fov_mask = pe.Node(niu.Function(function=_fill_with_ones),
                                name='fieldmap_fov_mask')

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

    apply_fov_mask = pe.Node(fsl.ApplyMask(), name="apply_fov_mask")

    enhance_and_skullstrip_epi_wf = init_enhance_and_skullstrip_epi_wf()

    workflow.connect([
        (inputnode, meta, [('name_source', 'in_file')]),
        (inputnode, fmap2ref_reg, [('fmap_ref', 'moving_image')]),
        (inputnode, fmap2ref_apply, [('in_reference', 'reference_image')]),
        (fmap2ref_reg, fmap2ref_apply, [('composite_transform', 'transforms')
                                        ]),
        (inputnode, fmap_mask2ref_apply, [('in_reference', 'reference_image')
                                          ]),
        (fmap2ref_reg, fmap_mask2ref_apply, [('composite_transform',
                                              'transforms')]),
        (inputnode, ds_reg_vsm, [('name_source', 'source_file')]),
        (fmap2ref_apply, ds_reg_vsm, [('out_report', 'in_file')]),
        (inputnode, fmap2ref_reg, [('in_reference_brain', 'fixed_image')]),
        (inputnode, ds_reg, [('name_source', 'source_file')]),
        (fmap2ref_reg, ds_reg, [('out_report', 'in_file')]),
        (inputnode, fmap2ref_apply, [('fmap', 'input_image')]),
        (inputnode, fmap_mask2ref_apply, [('fmap_mask', 'input_image')]),
        (fmap2ref_apply, torads, [('output_image', 'in_file')]),
        (meta, gen_vsm, [(('out_dict', _get_ec), 'dwell_time'),
                         (('out_dict', _get_pedir_fugue), 'unwarp_direction')
                         ]),
        (meta, vsm2dfm, [(('out_dict', _get_pedir_bids), 'pe_dir')]),
        (torads, gen_vsm, [('out', 'fmap_in_file')]),
        (vsm2dfm, unwarp_reference, [('out_file', 'transforms')]),
        (inputnode, unwarp_reference, [('in_reference', 'reference_image')]),
        (inputnode, unwarp_reference, [('in_reference', 'input_image')]),
        (vsm2dfm, outputnode, [('out_file', 'out_warp')]),
        (vsm2dfm, jac_dfm, [('out_file', 'deformationField')]),
        (inputnode, fieldmap_fov_mask, [('fmap_ref', 'in_file')]),
        (fieldmap_fov_mask, fmap_fov2ref_apply, [('out', 'input_image')]),
        (inputnode, fmap_fov2ref_apply, [('in_reference', 'reference_image')]),
        (fmap2ref_reg, fmap_fov2ref_apply, [('composite_transform',
                                             'transforms')]),
        (fmap_fov2ref_apply, apply_fov_mask, [('output_image', 'mask_file')]),
        (unwarp_reference, apply_fov_mask, [('output_image', 'in_file')]),
        (apply_fov_mask, enhance_and_skullstrip_epi_wf,
         [('out_file', 'inputnode.in_file')]),
        (apply_fov_mask, outputnode, [('out_file', 'out_reference')]),
        (enhance_and_skullstrip_epi_wf, outputnode,
         [('outputnode.mask_file', 'out_mask'),
          ('outputnode.out_report', 'out_mask_report'),
          ('outputnode.skull_stripped_file', 'out_reference_brain')]),
        (jac_dfm, outputnode, [('jacobian_image', 'out_jacobian')]),
    ])

    if not fmap_bspline:
        workflow.connect([(fmap_mask2ref_apply, gen_vsm, [('output_image',
                                                           'mask_file')])])

    if fmap_demean:
        # Demean within mask
        demean = pe.Node(niu.Function(function=_demean), name='demean')

        workflow.connect([
            (gen_vsm, demean, [('shift_out_file', 'in_file')]),
            (fmap_mask2ref_apply, demean, [('output_image', 'in_mask')]),
            (demean, vsm2dfm, [('out', 'in_file')]),
        ])

    else:
        workflow.connect([
            (gen_vsm, vsm2dfm, [('shift_out_file', 'in_file')]),
        ])

    return workflow
Example #5
0
def init_sdc_unwarp_wf(omp_nthreads, fmap_demean, debug, name='sdc_unwarp_wf'):
    """
    Apply the warping given by a displacements fieldmap.

    This workflow takes in a displacements fieldmap and calculates the corresponding
    displacements field (in other words, an ANTs-compatible warp file).

    It also calculates a new mask for the input dataset that takes into account the distortions.
    The mask is restricted to the field of view of the fieldmap since outside of it corrections
    could not be performed.

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

        from sdcflows.workflows.unwarp import init_sdc_unwarp_wf
        wf = init_sdc_unwarp_wf(omp_nthreads=8,
                                fmap_demean=True,
                                debug=False)


    Inputs

        in_reference
            the reference image
        in_reference_brain
            the reference image (skull-stripped)
        in_mask
            a brain mask corresponding to ``in_reference``
        metadata
            metadata associated to the ``in_reference`` EPI input
        fmap
            the fieldmap in Hz
        fmap_ref
            the reference (anatomical) image corresponding to ``fmap``
        fmap_mask
            a brain mask corresponding to ``fmap``


    Outputs

        out_reference
            the ``in_reference`` after unwarping
        out_reference_brain
            the ``in_reference`` after unwarping and skullstripping
        out_warp
            the corresponding :abbr:`DFM (displacements field map)` compatible with
            ANTs
        out_jacobian
            the jacobian of the field (for drop-out alleviation)
        out_mask
            mask of the unwarped input file

    """
    workflow = Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_reference', 'in_reference_brain', 'in_mask', 'metadata',
        'fmap_ref', 'fmap_mask', 'fmap'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=[
        'out_reference', 'out_reference_brain', 'out_warp', 'out_mask',
        'out_jacobian'
    ]),
                         name='outputnode')

    # Register the reference of the fieldmap to the reference
    # of the target image (the one that shall be corrected)
    ants_settings = pkgr.resource_filename('sdcflows',
                                           'data/fmap-any_registration.json')
    if debug:
        ants_settings = pkgr.resource_filename(
            'sdcflows', 'data/fmap-any_registration_testing.json')
    fmap2ref_reg = pe.Node(ANTSRegistrationRPT(
        generate_report=True,
        from_file=ants_settings,
        output_inverse_warped_image=True,
        output_warped_image=True),
                           name='fmap2ref_reg',
                           n_procs=omp_nthreads)

    ds_report_reg = pe.Node(DerivativesDataSink(desc='magnitude',
                                                suffix='bold'),
                            name='ds_report_reg',
                            mem_gb=0.01,
                            run_without_submitting=True)

    # Map the VSM into the EPI space
    fmap2ref_apply = pe.Node(ANTSApplyTransformsRPT(generate_report=True,
                                                    dimension=3,
                                                    interpolation='BSpline',
                                                    float=True),
                             name='fmap2ref_apply')

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

    ds_report_vsm = pe.Node(DerivativesDataSink(desc='fieldmap',
                                                suffix='bold'),
                            name='ds_report_vsm',
                            mem_gb=0.01,
                            run_without_submitting=True)

    # Fieldmap to rads and then to voxels (VSM - voxel shift map)
    torads = pe.Node(FieldToRadS(fmap_range=0.5), name='torads')

    get_ees = pe.Node(niu.Function(function=_get_ees, output_names=['ees']),
                      name='get_ees')

    gen_vsm = pe.Node(fsl.FUGUE(save_unmasked_shift=True), name='gen_vsm')
    # Convert the VSM into a DFM (displacements field map)
    # or: FUGUE shift to ANTS warping.
    vsm2dfm = pe.Node(itk.FUGUEvsm2ANTSwarp(), name='vsm2dfm')
    jac_dfm = pe.Node(ants.CreateJacobianDeterminantImage(
        imageDimension=3, outputImage='jacobian.nii.gz'),
                      name='jac_dfm')

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

    fieldmap_fov_mask = pe.Node(FilledImageLike(dtype='uint8'),
                                name='fieldmap_fov_mask')

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

    apply_fov_mask = pe.Node(fsl.ApplyMask(), name="apply_fov_mask")

    enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf(
        omp_nthreads=omp_nthreads, pre_mask=True)

    workflow.connect([
        (inputnode, fmap2ref_reg, [('fmap_ref', 'moving_image')]),
        (inputnode, fmap2ref_apply, [('in_reference', 'reference_image')]),
        (fmap2ref_reg, fmap2ref_apply, [('composite_transform', 'transforms')
                                        ]),
        (inputnode, fmap_mask2ref_apply, [('in_reference', 'reference_image')
                                          ]),
        (fmap2ref_reg, fmap_mask2ref_apply, [('composite_transform',
                                              'transforms')]),
        (fmap2ref_apply, ds_report_vsm, [('out_report', 'in_file')]),
        (inputnode, fmap2ref_reg, [('in_reference_brain', 'fixed_image')]),
        (fmap2ref_reg, ds_report_reg, [('out_report', 'in_file')]),
        (inputnode, fmap2ref_apply, [('fmap', 'input_image')]),
        (inputnode, fmap_mask2ref_apply, [('fmap_mask', 'input_image')]),
        (fmap2ref_apply, torads, [('output_image', 'in_file')]),
        (inputnode, get_ees, [('in_reference', 'in_file'),
                              ('metadata', 'in_meta')]),
        (fmap_mask2ref_apply, gen_vsm, [('output_image', 'mask_file')]),
        (get_ees, gen_vsm, [('ees', 'dwell_time')]),
        (inputnode, gen_vsm, [(('metadata', _get_pedir_fugue),
                               'unwarp_direction')]),
        (inputnode, vsm2dfm, [(('metadata', _get_pedir_bids), 'pe_dir')]),
        (torads, gen_vsm, [('out_file', 'fmap_in_file')]),
        (vsm2dfm, unwarp_reference, [('out_file', 'transforms')]),
        (inputnode, unwarp_reference, [('in_reference', 'reference_image')]),
        (inputnode, unwarp_reference, [('in_reference', 'input_image')]),
        (vsm2dfm, outputnode, [('out_file', 'out_warp')]),
        (vsm2dfm, jac_dfm, [('out_file', 'deformationField')]),
        (inputnode, fieldmap_fov_mask, [('fmap_ref', 'in_file')]),
        (fieldmap_fov_mask, fmap_fov2ref_apply, [('out_file', 'input_image')]),
        (inputnode, fmap_fov2ref_apply, [('in_reference', 'reference_image')]),
        (fmap2ref_reg, fmap_fov2ref_apply, [('composite_transform',
                                             'transforms')]),
        (fmap_fov2ref_apply, apply_fov_mask, [('output_image', 'mask_file')]),
        (unwarp_reference, apply_fov_mask, [('output_image', 'in_file')]),
        (apply_fov_mask, enhance_and_skullstrip_bold_wf,
         [('out_file', 'inputnode.in_file')]),
        (fmap_mask2ref_apply, enhance_and_skullstrip_bold_wf,
         [('output_image', 'inputnode.pre_mask')]),
        (apply_fov_mask, outputnode, [('out_file', 'out_reference')]),
        (enhance_and_skullstrip_bold_wf, outputnode,
         [('outputnode.mask_file', 'out_mask'),
          ('outputnode.skull_stripped_file', 'out_reference_brain')]),
        (jac_dfm, outputnode, [('jacobian_image', 'out_jacobian')]),
    ])

    if fmap_demean:
        # Demean within mask
        demean = pe.Node(DemeanImage(), name='demean')

        workflow.connect([
            (gen_vsm, demean, [('shift_out_file', 'in_file')]),
            (fmap_mask2ref_apply, demean, [('output_image', 'in_mask')]),
            (demean, vsm2dfm, [('out_file', 'in_file')]),
        ])

    else:
        workflow.connect([
            (gen_vsm, vsm2dfm, [('shift_out_file', 'in_file')]),
        ])

    return workflow
Example #6
0
def init_fmap2field_wf(omp_nthreads,
                       debug,
                       name='fmap2field_wf',
                       generate_report=True):
    """
    Convert the estimated fieldmap in Hz into a displacements field.

    This workflow takes in a fieldmap and calculates the corresponding
    displacements field (in other words, an ANTs-compatible warp file).

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

            from sdcflows.workflows.fmap import init_fmap2field_wf
            wf = init_fmap2field_wf(omp_nthreads=8,
                                    debug=False)

    Parameters
    ----------
    omp_nthreads : int
        Maximum number of threads an individual process may use.
    debug : bool
        Run fast configurations of registrations.
    name : str
        Unique name of this workflow.

    Inputs
    ------
    in_reference
        the reference image
    in_reference_brain
        the reference image (skull-stripped)
    metadata
        metadata associated to the ``in_reference`` EPI input
    fmap
        the fieldmap in Hz
    fmap_ref
        the reference (anatomical) image corresponding to ``fmap``
    fmap_mask
        a brain mask corresponding to ``fmap``


    Outputs
    -------
    out_reference
        the ``in_reference`` after unwarping
    out_reference_brain
        the ``in_reference`` after unwarping and skullstripping
    out_warp
        the corresponding :abbr:`DFM (displacements field map)` compatible with
        ANTs
    out_jacobian
        the jacobian of the field (for drop-out alleviation)
    out_mask
        mask of the unwarped input file

    """
    workflow = Workflow(name=name)
    workflow.__desc__ = """\
The *fieldmap* was then co-registered to the target EPI (echo-planar imaging)
reference run and converted to a displacements field map (amenable to registration
tools such as ANTs) with FSL's `fugue` and other *SDCflows* tools.
"""
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_reference', 'in_reference_brain', 'metadata', 'fmap_ref',
        'fmap_mask', 'fmap'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=['out_warp']),
                         name='outputnode')

    # Register the reference of the fieldmap to the reference
    # of the target image (the one that shall be corrected)
    ants_settings = pkgr.resource_filename('sdcflows',
                                           'data/fmap-any_registration.json')
    if debug:
        ants_settings = pkgr.resource_filename(
            'sdcflows', 'data/fmap-any_registration_testing.json')

    fmap2ref_reg = pe.Node(ANTSRegistrationRPT(
        generate_report=False,
        from_file=ants_settings,
        output_inverse_warped_image=True,
        output_warped_image=True),
                           name='fmap2ref_reg',
                           n_procs=omp_nthreads)

    # Map the VSM into the EPI space
    fmap2ref_apply = pe.Node(ANTSApplyTransformsRPT(generate_report=False,
                                                    dimension=3,
                                                    interpolation='BSpline',
                                                    float=True),
                             name='fmap2ref_apply')

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

    # Fieldmap to rads and then to voxels (VSM - voxel shift map)
    torads = pe.Node(FieldToRadS(fmap_range=0.5), name='torads')

    get_ees = pe.Node(niu.Function(function=_get_ees, output_names=['ees']),
                      name='get_ees')

    gen_vsm = pe.Node(fsl.FUGUE(save_unmasked_shift=True), name='gen_vsm')
    # Convert the VSM into a DFM (displacements field map)
    # or: FUGUE shift to ANTS warping.
    vsm2dfm = pe.Node(FUGUEvsm2ANTSwarp(), name='vsm2dfm')

    workflow.connect([
        (inputnode, fmap2ref_reg, [('fmap_ref', 'moving_image'),
                                   ('in_reference_brain', 'fixed_image')]),
        (inputnode, fmap2ref_apply, [('fmap', 'input_image'),
                                     ('in_reference', 'reference_image')]),
        (inputnode, fmap_mask2ref_apply, [('in_reference', 'reference_image'),
                                          ('fmap_mask', 'input_image')]),
        (inputnode, get_ees, [('in_reference', 'in_file'),
                              ('metadata', 'in_meta')]),
        (inputnode, gen_vsm, [(('metadata', _get_pedir_fugue),
                               'unwarp_direction')]),
        (inputnode, vsm2dfm, [(('metadata', _get_pedir_bids), 'pe_dir')]),
        (fmap2ref_reg, fmap2ref_apply, [('composite_transform', 'transforms')
                                        ]),
        (fmap2ref_reg, fmap_mask2ref_apply, [('composite_transform',
                                              'transforms')]),
        (fmap2ref_apply, torads, [('output_image', 'in_file')]),
        (fmap_mask2ref_apply, gen_vsm, [('output_image', 'mask_file')]),
        (gen_vsm, vsm2dfm, [('shift_out_file', 'in_file')]),
        (get_ees, gen_vsm, [('ees', 'dwell_time')]),
        (torads, gen_vsm, [('out_file', 'fmap_in_file')]),
        (vsm2dfm, outputnode, [('out_file', 'out_warp')]),
    ])

    if generate_report:
        from niworkflows.interfaces.bids import DerivativesDataSink
        from ..interfaces.reportlets import FieldmapReportlet

        fmap_rpt = pe.Node(FieldmapReportlet(reference_label='EPI Reference',
                                             moving_label='Magnitude',
                                             show='both'),
                           name='fmap_rpt')
        ds_report_sdc = pe.Node(DerivativesDataSink(desc='fieldmap',
                                                    suffix='bold'),
                                name='ds_report_fmap',
                                mem_gb=0.01,
                                run_without_submitting=True)

        workflow.connect([
            (inputnode, fmap_rpt, [('in_reference', 'reference')]),
            (fmap2ref_reg, fmap_rpt, [('warped_image', 'moving')]),
            (fmap_mask2ref_apply, fmap_rpt, [('output_image', 'mask')]),
            (vsm2dfm, fmap_rpt, [('fieldmap', 'fieldmap')]),
            (fmap_rpt, ds_report_sdc, [('out_report', 'in_file')]),
        ])

    return workflow