Exemplo n.º 1
0
def eddy_fsl_pipeline(epi_param, name="eddy_fsl"):
    """
    Using eddy from fsl for head motion correction and eddy current distortion correction.

    """
    import nipype.interfaces.utility as niu  # utility
    import nipype.pipeline.engine as pe  # pypeline engine
    from nipype.interfaces.fsl import Eddy

    from clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils import (
        b0_indices,
        eddy_fsl,
        generate_acq,
        generate_index,
    )

    inputnode = pe.Node(
        niu.IdentityInterface(
            fields=["in_file", "in_bvec", "in_bval", "in_mask", "ref_b0"]),
        name="inputnode",
    )

    generate_acq = pe.Node(
        niu.Function(
            function=generate_acq,
            input_names=["in_b0", "epi_param"],
            output_names=["out_file"],
        ),
        name="generate_acq",
    )
    generate_acq.inputs.epi_param = epi_param

    list_b0 = pe.Node(
        niu.Function(input_names=["in_bval"],
                     output_names=["out_idx"],
                     function=b0_indices),
        name="find_b0_indices",
    )

    generate_index = pe.Node(
        niu.Function(
            function=generate_index,
            input_names=["in_bval", "b0_index"],
            output_names=["eddy_index"],
        ),
        name="generate_index",
    )

    eddy = pe.Node(
        niu.Function(
            input_names=[
                "in_bvec",
                "in_bval",
                "in_file",
                "in_mask",
                "in_acqp",
                "in_index",
            ],
            output_names=[
                "out_parameter", "out_corrected", "out_rotated_bvecs"
            ],
            function=eddy_fsl,
        ),
        name="eddy_fsl",
    )

    eddy = pe.Node(interface=Eddy(), name="eddy_fsl")
    eddy.inputs.flm = "linear"

    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["out_parameter", "out_corrected", "out_rotated_bvecs"]),
        name="outputnode",
    )

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode, generate_acq, [("ref_b0", "in_b0")]),
        (inputnode, generate_index, [("in_bval", "in_bval")]),
        (list_b0, generate_index, [("out_idx", "b0_index")]),
        (inputnode, list_b0, [("in_bval", "in_bval")]),
        (inputnode, eddy, [("in_bvec", "in_bvec")]),
        (inputnode, eddy, [("in_bval", "in_bval")]),
        (inputnode, eddy, [("in_file", "in_file")]),
        (inputnode, eddy, [("in_mask", "in_mask")]),
        (generate_acq, eddy, [("out_file", "in_acqp")]),
        (generate_index, eddy, [("eddy_index", "in_index")]),
        (eddy, outputnode, [("out_parameter", "out_parameter")]),
        (eddy, outputnode, [("out_corrected", "out_corrected")]),
        (eddy, outputnode, [("out_rotated_bvecs", "out_rotated_bvecs")]),
    ])
    return wf
Exemplo n.º 2
0
    def __init__(self, parent, dir_dic, bids):
        super().__init__(parent, dir_dic, bids)

        # Create interfaces ============================================================================================
        # BET
        T1w_BET = Node(BET(), name="T1w_BET")
        T1w_BET.btn_string = 'T1w Brain Extraction'
        self.interfaces.append(T1w_BET)

        T1w_gad_BET = Node(BET(), name="T1w_gad_BET")
        T1w_gad_BET.btn_string = 'T1w Gadolinium Enhanced Brain Extraction'
        self.interfaces.append(T1w_gad_BET)

        T2w_dbs_BET = Node(BET(), name="T2w_dbs_BET")
        T2w_dbs_BET.btn_string = 'T2w DBS Acquisition Brain Extraction'
        self.interfaces.append(T2w_dbs_BET)

        dwi_BET = Node(BET(), name="dwi_BET")
        dwi_BET.btn_string = 'dwi Brain Extraction'
        self.interfaces.append(dwi_BET)

        # BFC
        T1w_BFC = Node(N4BiasFieldCorrection(), name="T1w_BFC")
        T1w_BFC.btn_string = 'T1w Bias Field Correction'
        self.interfaces.append(T1w_BFC)

        # Split
        dwi_ROI_b0 = Node(ExtractROI(), name="dwi_ROI_b0")
        dwi_ROI_b0.btn_string = 'dwi Extract b0'
        self.interfaces.append(dwi_ROI_b0)

        # Eddy current correction
        dwi_Eddy = Node(Eddy(), name="dwi_Eddy")
        dwi_Eddy.btn_string = 'dwi Eddy Current Correction'
        self.interfaces.append(dwi_Eddy)

        # Distortion correction
        # as this section is script/comment heavy it was put into a function
        self.distortion_correction_workflow()

        # Data output (i.e. sink) ======================================================================================
        self.sink = Node(DataSink(), name="sink")
        self.sink.btn_string = 'data sink'
        self.sink.inputs.base_directory = self.dir_dic['data_dir']

        self.jsink = Node(JSONFileSink(), name="jsink")
        self.jsink.btn_string = 'json sink'
        self.jsink.inputs.base_directory = self.dir_dic['data_dir']

        # Initialize workflow ==========================================================================================
        self.wf = Workflow(name='pre_processing')

        # T1w BET to ants N4BiasFieldCorrection
        self.wf.connect([(self.return_interface("T1w_BET"),
                          self.return_interface("T1w_BFC"),
                          [("out_file", "input_image")])])
        self.wf.connect([(self.return_interface("T1w_BET"),
                          self.return_interface("T1w_BFC"), [("mask_file",
                                                              "mask_image")])])

        # Eddy
        self.wf.connect([(self.return_interface("dwi_BET"),
                          self.return_interface("dwi_Eddy"), [("out_file",
                                                               "in_file")])])

        self.wf.connect([(self.return_interface("dwi_BET"),
                          self.return_interface("dwi_Eddy"), [("mask_file",
                                                               "in_mask")])])

        # ROI b0
        self.wf.connect([(self.return_interface("dwi_Eddy"),
                          self.return_interface("dwi_ROI_b0"),
                          [("out_corrected", "in_file")])])

        # Distortion Correction:
        # b0_T1_Reg:
        #   -i: moving image
        #   -r: T1
        #   -x: T1 mask
        self.wf.connect([(self.return_interface("dwi_ROI_b0"),
                          self.return_interface("b0_T1w_Reg"),
                          [("roi_file", "moving_image")])])

        self.wf.connect([(self.return_interface("T1w_BFC"),
                          self.return_interface("b0_T1w_Reg"),
                          [("output_image", "fixed_image")])])

        # test remove as doesn't seem useful (see self.distortion_correction_workflow()) and causes a crash when added
        # self.wf.connect([(self.return_interface("T1w_BET"), self.return_interface("b0_T1w_Reg"),
        #                   [("mask_file", "fixed_image_mask")])])

        # dwi_T1_Tran:
        #   -i: Eddy corrected image
        #   -r: Eddy corrected b0
        #   -t: transforms
        self.wf.connect([(self.return_interface("dwi_Eddy"),
                          self.return_interface("dwi_T1w_Tran"),
                          [("out_corrected", "input_image")])])

        self.wf.connect([(self.return_interface("dwi_ROI_b0"),
                          self.return_interface("dwi_T1w_Tran"),
                          [("roi_file", "reference_image")])])

        self.wf.connect([(self.return_interface("b0_T1w_Reg"),
                          self.return_interface("dwi_T1w_Tran"),
                          [("composite_transform", "transforms")])])

        # BaseInterface generates a dict mapping button strings to the workflow nodes
        # self.map_workflow()
        graph_file = self.wf.write_graph("pre_processing", graph2use='flat')
        self.graph_file = graph_file.replace("pre_processing.png",
                                             "pre_processing_detailed.png")

        self.init_settings()
        self.init_ui()
import os 
from os.path import abspath
from datetime import datetime
from IPython.display import Image
import pydot
from nipype import Workflow, Node, MapNode, Function, config
from nipype.interfaces.fsl import TOPUP, ApplyTOPUP, BET, ExtractROI,  Eddy, FLIRT, FUGUE
from nipype.interfaces.fsl.maths import MathsCommand
import nipype.interfaces.utility as util 
import nipype.interfaces.mrtrix3 as mrt
#Requirements for the workflow to run smoothly: All files as in NIfTI-format and named according to the following standard: 
#Images are from the tonotopy DKI sequences on the 7T Philips Achieva scanner in Lund. It should work with any DKI sequence and possibly also a standard DTI but the setting for B0-corrections, epi-distortion corrections and eddy current corrections will be wrong. 
#DKI file has a base name shared with bvec and bval in FSL format. E.g. "DKI.nii.gz" "DKI.bvec" and "DKI.bval". 
#There is one b0-volume with reversed (P->A) phase encoding called DKIbase+_revenc. E.g. "DKI_revenc.nii.gz". 
#Philips B0-map magnitude and phase offset (in Hz) images. 
#One input file for topup describing the images as specified by topup. 
#Set nbrOfThreads to number of available CPU threads to run the analyses. 
### Need to make better revenc for the 15 version if we choose to use it (i.e. same TE and TR)
#Set to relevant directory/parameters
datadir=os.path.abspath("/Users/ling-men/Documents/MRData/testDKI")
rawDKI_base='DKI_15' 
B0map_base = 'B0map'
nbrOfThreads=6
print_graph = True 
acqparam_file = os.path.join(datadir,'acqparams.txt')
index_file = os.path.join(datadir,'index.txt')
####
#config.enable_debug_mode()
DKI_nii=os.path.join(datadir, rawDKI_base+'.nii.gz')
DKI_bval=os.path.join(datadir, rawDKI_base+'.bval')
Exemplo n.º 4
0
 "binary_maths": {BinaryMaths().version: BinaryMaths},
 "BET": {BET().version: BET},
 "CAT12 Segmentation": {"12.7": Cat12Segmentation},
 "fslmerge": {Merge().version: Merge},
 "fslreorient2std": {Reorient2Std().version: Reorient2Std},
 "fslroi": {ExtractROI().version: ExtractROI},
 "FAST": {FastWrapper.version: FastWrapper},
 "FLIRT": {FLIRT().version: FLIRT},
 "FNIRT": {FNIRT().version: FNIRT},
 "FSL Anatomical Processing Script": {FslAnat.__version__: FslAnat},
 "mean_image": {MeanImage().version: MeanImage},
 "robustfov": {RobustFOV().version: RobustFOV},
 "ReconAll": {ReconAll().version: ReconAll},
 "SUSAN": {SUSAN().version: SUSAN},
 "topup": {TopupWrapper.version: TopupWrapper},
 "eddy": {Eddy().version: Eddy},
 "denoise": {DWIDenoise().version: DWIDenoise},
 "degibbs": {MRDeGibbs().version: MRDeGibbs},
 "bias_correct": {DWIBiasCorrect().version: DWIBiasCorrect},
 "dwifslpreproc": {DwiFslPreproc.__version__: DwiFslPreproc},
 "mrconvert": {MRConvert.__version__: MRConvert},
 "dwi2fod": {
     ConstrainedSphericalDeconvolution().version: ConstrainedSphericalDeconvolution  # noqa: E501
 },
 "dwi2response": {ResponseSD().version: ResponseSD},
 "5ttgen": {Generate5tt().version: Generate5tt},
 "dwi2tensor": {Dwi2Tensor.__version__: Dwi2Tensor},
 "tensor2metric": {Tensor2metric.__version__: Tensor2metric},
 "mrcat": {MRCat.__version__: MRCat},
 "dwigradcheck": {DwiGradCheck.__version__: DwiGradCheck},
 "Mutual Information Score": {"1.0": MutualInformationScore},
Exemplo n.º 5
0
def dti_artifact_correction(wf_name="dti_artifact_correction"):
    """ Run the diffusion MRI pre-processing workflow against the diff files in `data_dir`.

    It will resample/regrid the diffusion image to have isometric voxels.
    Corrects for head motion correction and Eddy currents.
    Estimates motion outliers and exports motion reports using nipype.algorithms.RapidArt.

    Nipype Inputs
    -------------
    dti_art_input.diff: traits.File
        path to the diffusion MRI image

    dti_art_input.bval: traits.File
        path to the bvals file

    dti_art_input.bvec: traits.File
        path to the bvecs file


    Nipype Outputs
    --------------
    dti_art_output.eddy_corr_file: traits.File
        Eddy currents corrected DTI image.

    dti_art_output.bvec_rotated: traits.File
        Rotated bvecs file

    dti_art_output.brain_mask_1: traits.File
        Brain mask extracted using BET on the first B0 image.

    dti_art_output.brain_mask_2: traits.File
        Brain mask extracted using BET on the average B0 image,
        after motion correction.

    dti_art_output.acpq: traits.File
        Text file with acquisition parameters calculated for Eddy.

    dti_art_output.index: traits.File
        Text file with acquisition indices calculated for Eddy.

    dti_art_output.avg_b0: traits.File
        The average b=0 image extracted from the motion and eddy
        currents correted diffusion MRI.

    dti_art_output.hmc_corr_file: traits.File

    dti_art_output.hmc_corr_bvec: traits.File

    dti_art_output.hmc_corr_xfms: traits.File

    dti_art_output.art_displacement_files: traits.File

    dti_art_output.art_intensity_files: traits.File

    dti_art_output.art_norm_files: traits.File

    dti_art_output.art_outlier_files: traits.File

    dti_art_output.art_plot_files: traits.File

    dti_art_output.art_statistic_files: traits.File

    Returns
    -------
    wf: nipype Workflow
    """
    # specify input and output fields
    in_fields  = ["diff", "bval", "bvec"]
    out_fields = ["eddy_corr_file",
                  "bvec_rotated",
                  "brain_mask_1",
                  "brain_mask_2",
                  "acqp",
                  "index",
                  "avg_b0",
                 ]

    do_rapidart = get_config_setting("dmri.artifact_detect", True)
    if do_rapidart:
        out_fields += ["hmc_corr_file",
                       "hmc_corr_bvec",
                       "hmc_corr_xfms",
                       "art_displacement_files",
                       "art_intensity_files",
                       "art_norm_files",
                       "art_outlier_files",
                       "art_plot_files",
                       "art_statistic_files",
                      ]

    # input interface
    dti_input = setup_node(IdentityInterface(fields=in_fields, mandatory_inputs=True),
                           name="dti_art_input")

    # resample
    resample = setup_node(Function(function=reslice,
                                   input_names=['in_file', 'new_zooms', 'order', 'out_file'],
                                   output_names=['out_file']),
                          name='dti_reslice')

    ## extract first b0 for Eddy and HMC brain mask
    list_b0 = pe.Node(Function(function=b0_indices,
                               input_names=['in_bval'],
                               output_names=['out_idx'],),
                               name='b0_indices')

    extract_b0 = pe.Node(ExtractROI(t_size=1),
                         name="extract_first_b0")

    # For Eddy, the mask is only used for selecting voxels for the estimation of the hyperparameters,
    # so isn’t very critical.
    # Note also that it is better with a too conservative (small) mask than a too big.
    bet_dwi0 = setup_node(BET(frac=0.3, mask=True, robust=True),
                          name='bet_dwi_pre')

    pick_first = lambda lst: lst[0]

    # motion artifacts detection, requires linear co-registration for motion estimation.
    if do_rapidart:
        # head motion correction
        hmc = hmc_pipeline()

        art = setup_node(rapidart_dti_artifact_detection(), name="detect_artifacts")

    # Eddy
    eddy = setup_node(Eddy(method='jac'), name="eddy")

    ## acquisition parameters for Eddy
    write_acqp = setup_node(Function(function=dti_acquisition_parameters,
                                     input_names=["in_file"],
                                     output_names=["out_acqp", "out_index"],),
                            name="write_acqp")

    ## rotate b-vecs
    rot_bvec = setup_node(Function(function=eddy_rotate_bvecs,
                                   input_names=["in_bvec", "eddy_params"],
                                   output_names=["out_file"],),
                          name="rot_bvec")

    ## extract all b0s and average them after Eddy correction
    avg_b0_post = pe.Node(Function(function=b0_average,
                                   input_names=['in_dwi', 'in_bval'],
                                   output_names=['out_file'],),
                          name='b0_avg_post')

    bet_dwi1 = setup_node(BET(frac=0.3, mask=True, robust=True),
                          name='bet_dwi_post')

    # nlmeans denoise
    apply_nlmeans = get_config_setting("dmri.apply_nlmeans", True)
    if apply_nlmeans:
        nlmeans = setup_node(Function(function=nlmeans_denoise,
                                      input_names=['in_file', 'mask_file', 'out_file', 'N'],
                                      output_names=['out_file']),
                             name='nlmeans_denoise')

    # output interface
    dti_output = setup_node(IdentityInterface(fields=out_fields),
                            name="dti_art_output")

    # Create the workflow object
    wf = pe.Workflow(name=wf_name)

    # Connect the nodes
    wf.connect([
                # resample to iso-voxel
                (dti_input, resample, [("diff", "in_file"),]),

                # read from input file the acquisition parameters for eddy
                (dti_input, write_acqp, [("diff", "in_file")]),

                # reference mask for hmc and eddy
                (dti_input,  list_b0,    [("bval",     "in_bval")]),
                (resample,   extract_b0, [("out_file", "in_file")]),
                (list_b0,    extract_b0, [(("out_idx", pick_first), "t_min")]),

                (extract_b0, bet_dwi0,   [("roi_file", "in_file")]),

                # Eddy
                (resample,   eddy, [("out_file",  "in_file")]),
                (bet_dwi0,   eddy, [("mask_file", "in_mask")]),
                (dti_input,  eddy, [("bval",      "in_bval"),
                                    ("bvec",      "in_bvec")
                                   ]),
                (write_acqp, eddy, [("out_acqp",  "in_acqp"),
                                    ("out_index", "in_index")
                                   ]),

                # rotate bvecs
                (dti_input, rot_bvec, [("bvec",          "in_bvec")]),
                (eddy,      rot_bvec, [("out_parameter", "eddy_params")]),

                # final avg b0
                (dti_input,   avg_b0_post, [("bval",          "in_bval")]),
                (eddy,        avg_b0_post, [("out_corrected", "in_dwi" )]),
                (avg_b0_post, bet_dwi1,    [("out_file",      "in_file")]),

                # output
                (write_acqp,  dti_output,  [("out_acqp",  "acqp"),
                                            ("out_index", "index")]),
                (bet_dwi0,    dti_output,  [("mask_file", "brain_mask_1")]),
                (bet_dwi1,    dti_output,  [("mask_file", "brain_mask_2")]),
                (rot_bvec,    dti_output,  [("out_file",  "bvec_rotated")]),
                (avg_b0_post, dti_output,  [("out_file",  "avg_b0")]),
              ])

    if apply_nlmeans:
        wf.connect([
                    # non-local means
                    (eddy,     nlmeans,   [("out_corrected", "in_file")]),
                    (bet_dwi1, nlmeans,   [("mask_file",     "mask_file")]),

                    # output
                    (nlmeans, dti_output, [("out_file", "eddy_corr_file")]),
                   ])
    else:
        wf.connect([
                    # output
                    (eddy, dti_output, [("out_corrected", "eddy_corr_file")]),
                   ])

    if do_rapidart:
        wf.connect([
                    # head motion correction
                    (dti_input, hmc, [("bval", "inputnode.in_bval"),
                                      ("bvec", "inputnode.in_bvec"),
                                     ]),
                    (resample,  hmc, [("out_file",              "inputnode.in_file")]),
                    (bet_dwi0,  hmc, [("mask_file",             "inputnode.in_mask")]),
                    (list_b0,   hmc, [(("out_idx", pick_first), "inputnode.ref_num"),]),

                    # artifact detection
                    (hmc,      art, [("outputnode.out_file", "realigned_files"),
                                     ("outputnode.out_xfms", "realignment_parameters"),
                                    ]),
                    (bet_dwi1, art, [("mask_file", "mask_file"),]),

                    # output
                    (hmc, dti_output, [("outputnode.out_file", "hmc_corr_file"),
                                       ("outputnode.out_bvec", "hmc_corr_bvec"),
                                       ("outputnode.out_xfms", "hmc_corr_xfms"),
                                      ]),

                    (art, dti_output, [("displacement_files",  "art_displacement_files"),
                                       ("intensity_files",     "art_intensity_files"),
                                       ("norm_files",          "art_norm_files"),
                                       ("outlier_files",       "art_outlier_files"),
                                       ("plot_files",          "art_plot_files"),
                                       ("statistic_files",     "art_statistic_files"),
                                      ]),
                  ])

    return wf
Exemplo n.º 6
0
     "versions": [{
         "title": ApplyTOPUP().version or "1.0",
         "description":
         f"Default apply_topup version for nipype {_NIPYPE_VERSION}.",  # noqa: E501
         "input": APPLY_TOPUP_INPUT_SPECIFICATION,
         "output": APPLY_TOPUP_OUTPUT_SPECIFICATION,
         "nested_results_attribute": "outputs.get_traitsfree",
     }],
 },
 {
     "title":
     "eddy",
     "description":
     "estimates and corrects eddy currents induced distortions.",  # noqa: E501
     "versions": [{
         "title": Eddy().version or "1.0",
         "description":
         f"Default eddy version for nipype {_NIPYPE_VERSION}.",  # noqa: E501
         "input": EDDY_INPUT_SPECIFICATION,
         "output": EDDY_OUTPUT_SPECIFICATION,
         "nested_results_attribute": "outputs.get_traitsfree",
     }],
 },
 {
     "title":
     "binary_maths",
     "description":
     "Perform mathematical operations using a second image or a numeric value.",  # noqa: E501
     "versions": [{
         "title": BinaryMaths().version or "1.0",
         "description":
Exemplo n.º 7
0
def eddy_fsl_pipeline(epi_param, name='eddy_fsl'):
    """
    Using eddy from fsl for head motion correction and eddy current distortion correction.

    """
    from nipype.interfaces.fsl import Eddy
    import nipype.interfaces.utility as niu     # utility
    import nipype.pipeline.engine as pe          # pypeline engine
    from clinica.pipelines.dwi_preprocessing_using_t1.dwi_preprocessing_using_t1_utils import eddy_fsl, generate_acq, generate_index, b0_indices

    inputnode = pe.Node(
            niu.IdentityInterface(
                fields=['in_file',
                        'in_bvec',
                        'in_bval',
                        'in_mask',
                        'ref_b0']),
            name='inputnode')

    generate_acq = pe.Node(niu.Function(function=generate_acq,
                                        input_names=['in_b0', 'epi_param'],
                                        output_names=['out_file']),
                           name='generate_acq')
    generate_acq.inputs.epi_param = epi_param

    list_b0 = pe.Node(niu.Function(input_names=['in_bval'],
                                   output_names=['out_idx'],
                                   function=b0_indices),
                      name='find_b0_indices')

    generate_index = pe.Node(niu.Function(function=generate_index,
                                          input_names=['in_bval', 'b0_index'],
                                          output_names=['eddy_index']),
                             name='generate_index')

    eddy = pe.Node(niu.Function(input_names=['in_bvec', 'in_bval', 'in_file', 'in_mask', 'in_acqp', 'in_index'],
                                output_names=['out_parameter', 'out_corrected', 'out_rotated_bvecs'],
                                function=eddy_fsl),
                   name='eddy_fsl')

    eddy = pe.Node(interface=Eddy(), name='eddy_fsl')
    eddy.inputs.flm = 'linear'

    outputnode = pe.Node(niu.IdentityInterface(fields=['out_parameter',
                                                       'out_corrected',
                                                       'out_rotated_bvecs']),
                         name='outputnode')

    wf = pe.Workflow(name=name)
    wf.connect([
        (inputnode,     generate_acq,   [('ref_b0', 'in_b0')]),
        (inputnode,  generate_index,      [('in_bval', 'in_bval')]),
        (list_b0,  generate_index,      [('out_idx', 'b0_index')]),
        (inputnode,      list_b0,      [('in_bval', 'in_bval')]),

        (inputnode,      eddy,     [('in_bvec', 'in_bvec')]),
        (inputnode,      eddy,     [('in_bval', 'in_bval')]),
        (inputnode,  eddy,   [('in_file', 'in_file')]),
        (inputnode,     eddy,   [('in_mask', 'in_mask')]),
        (generate_acq,      eddy, [('out_file', 'in_acqp')]),
        (generate_index,      eddy, [('eddy_index', 'in_index')]),

        (eddy,   outputnode, [('out_parameter', 'out_parameter')]),
        (eddy,      outputnode, [('out_corrected', 'out_corrected')]),
        (eddy,      outputnode, [('out_rotated_bvecs', 'out_rotated_bvecs')])
    ])
    return wf
Exemplo n.º 8
0
def init_eddy_wf(debug=False, name="eddy_wf"):
    """
    Create a workflow for head-motion & Eddy currents distortion estimation with FSL.

    Parameters
    ----------
    name : :obj:`str`
        Name of workflow (default: ``eddy_wf``)

    Inputs
    ------
    dwi_file
        dwi NIfTI file

    Outputs
    -------
    out_eddy
        The eddy corrected diffusion image..

    """
    from nipype.interfaces.fsl import Eddy, ExtractROI

    inputnode = pe.Node(
        niu.IdentityInterface(
            fields=["dwi_file", "metadata", "dwi_mask", "in_bvec", "in_bval"]
        ),
        name="inputnode",
    )

    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["out_rotated_bvecs", "eddy_ref_image", "out_eddy"]
        ),
        name="outputnode",
    )

    workflow = Workflow(name=name)
    workflow.__desc__ = f"""\
Geometrical distortions derived from the so-called Eddy-currents, and head-motion
realignment parameters were estimated with the joint modeling of ``eddy_openmp``,
included in FSL {Eddy().version} [@eddy].
"""
    eddy = pe.Node(
        Eddy(),
        name="eddy",
    )

    if debug:
        eddy.inputs.niter = 1
        eddy.inputs.is_shelled = True
        eddy.inputs.dont_peas = True
        eddy.inputs.nvoxhp = 100

    # Generate the acqp and index files for eddy
    gen_eddy_files = pe.Node(
        niu.Function(
            input_names=["in_file", "in_meta"],
            output_names=["out_acqparams", "out_index"],
            function=gen_eddy_textfiles,
        ),
        name="gen_eddy_files",
    )

    eddy_ref_img = pe.Node(ExtractROI(t_min=0, t_size=1), name="eddy_roi")

    # fmt:off
    workflow.connect([
        (inputnode, eddy, [
            ("dwi_file", "in_file"),
            ("dwi_mask", "in_mask"),
            ("in_bvec", "in_bvec"),
            ("in_bval", "in_bval"),
        ]),
        (inputnode, gen_eddy_files, [
            ("dwi_file", "in_file"),
            ("metadata", "in_meta")
        ]),
        (gen_eddy_files, eddy, [
            ("out_acqparams", "in_acqp"),
            ("out_index", "in_index"),
        ]),
        (eddy, outputnode, [
            ("out_corrected", "out_eddy"),
            ("out_rotated_bvecs", "out_rotated_bvecs")
        ]),
        (eddy, eddy_ref_img, [("out_corrected", "in_file")]),
        (eddy_ref_img, outputnode, [("roi_file", "eddy_ref_image")]),
    ])
    # fmt:on
    return workflow