def brainsuite_susceptibility_correction(outdir,
                                         dwi,
                                         bval,
                                         bvec,
                                         subject_id,
                                         phase_enc_dir,
                                         subjects_dir=None,
                                         qc_dir=None,
                                         bdp_nthread=4):
    """
    Assuming the beginning of the preprocessing was done with Connectomist
    up to Eddy current and motion correction, we now want to make susceptbility
    distortion correction using Brainsuite.

    Parameters
    ----------
    outdir: str
        Path to directory where to output.
    dwi: str
        Path to the preprocessed diffusion-weighted Nifti.
    bval: str
        Path to the bval file associated to the Nifti.
    bvec: str
        Path to the bvec file associated to the Nifti.
    subject_id: str
        Subject identifier used in Freesurfer.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subjects_dir: str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    qc_dir: str, default None
        Path to directory where to output snapshots for QC. By default in
        outdir.
    bdp_nthread: int, default 4
        Number of threads for bdp (see bdp.sh --thread flag)
    """

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Check in plane phase encoding direction
    # The sign of the phase encoding direction has no impact in this strategy
    # e.g. for "+y" or "-y" use "y"
    possible_phase_enc_dirs = {"y", "x"}
    if phase_enc_dir not in possible_phase_enc_dirs:
        raise ValueError(
            "Bad argument 'phase_enc_dir': {}, should be in {}.".format(
                phase_enc_dir, possible_phase_enc_dirs))

    # Set and check path to T1 brain-only volume from Freesurfer (mgz format)
    t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz")
    if not os.path.isfile(t1_brain_mgz):
        raise Exception("Missing file: {}".format(t1_brain_mgz))

    # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the
    # same orientation as the diffusion data)
    t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz")
    cmd = [
        "mri_convert", t1_brain_mgz, t1_brain_RAS_nii, "--out_orientation",
        "RAS"
    ]
    run_freesurfer_cmd(cmd, subjects_dir=subjects_dir)

    # Run bfc (bias correction: required by BrainSuite)
    t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz")
    cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc]
    subprocess.check_call(cmd)

    # Extract brain from the nodif volume with FSL bet2
    nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz")
    bet2(dwi, nodif_brain, f=0.25, m=False)

    # Run bdp.sh: registration + diffusion model
    cmd = [
        "bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec,
        "--dwi-mask", nodif_brain,
        "--dir=%s" % phase_enc_dir,
        "--threads=%i" % bdp_nthread
    ]
    subprocess.check_call(cmd)

    # Path to files of interest, created by BrainSuite bdp.sh
    dwi_wo_susceptibility = os.path.join(outdir,
                                         "t1_brain.dwi.RAS.correct.nii.gz")

    ###############
    # Quality check: create snapshots to visually assert the registration
    # quality

    if qc_dir is None:
        qc_dir = outdir

    # The snapshots won't contain all slices, half of them
    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Path to registered T1
    t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz")

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(qc_dir, "t1_with_nodif_edges.png")
    plot_image(t1_to_dif,
               edge_file=nodif_brain,
               snap_file=t1_with_nodif_edges_png,
               name="T1 in diffusion + edges of nodif",
               cut_coords=nb_slices_in_z - 2)

    # Second png: nodif with edges of T1 registered in diffusion
    nodif_with_t1_edges_png = os.path.join(qc_dir, "nodif_with_t1_edges.png")
    plot_image(nodif_brain,
               edge_file=t1_to_dif,
               snap_file=nodif_with_t1_edges_png,
               name="nodif + edges of registered T1",
               cut_coords=nb_slices_in_z - 2)

    return dwi_wo_susceptibility, bval, bvec
def brainsuite_susceptibility_correction(outdir,
                                         dwi,
                                         bval,
                                         bvec,
                                         subject_id,
                                         phase_enc_dir,
                                         subjects_dir=None,
                                         qc_dir=None,
                                         bdp_nthread=4):
    """
    Assuming the beginning of the preprocessing was done with Connectomist
    up to Eddy current and motion correction, we now want to make susceptbility
    distortion correction using Brainsuite.

    Parameters
    ----------
    outdir: str
        Path to directory where to output.
    dwi: str
        Path to the preprocessed diffusion-weighted Nifti.
    bval: str
        Path to the bval file associated to the Nifti.
    bvec: str
        Path to the bvec file associated to the Nifti.
    subject_id: str
        Subject identifier used in Freesurfer.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subjects_dir: str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    qc_dir: str, default None
        Path to directory where to output snapshots for QC. By default in
        outdir.
    bdp_nthread: int, default 4
        Number of threads for bdp (see bdp.sh --thread flag)
    """

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Check in plane phase encoding direction
    # The sign of the phase encoding direction has no impact in this strategy
    # e.g. for "+y" or "-y" use "y"
    possible_phase_enc_dirs = {"y", "x"}
    if phase_enc_dir not in possible_phase_enc_dirs:
        raise ValueError("Bad argument 'phase_enc_dir': {}, should be in {}."
                         .format(phase_enc_dir, possible_phase_enc_dirs))

    # Set and check path to T1 brain-only volume from Freesurfer (mgz format)
    t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz")
    if not os.path.isfile(t1_brain_mgz):
        raise Exception("Missing file: {}".format(t1_brain_mgz))

    # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the
    # same orientation as the diffusion data)
    t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz")
    cmd = ["mri_convert", t1_brain_mgz, t1_brain_RAS_nii,
           "--out_orientation", "RAS"]
    run_freesurfer_cmd(cmd, subjects_dir=subjects_dir)

    # Run bfc (bias correction: required by BrainSuite)
    t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz")
    cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc]
    subprocess.check_call(cmd)

    # Extract brain from the nodif volume with FSL bet2
    nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz")
    bet2(dwi, nodif_brain, f=0.25, m=False)

    # Run bdp.sh: registration + diffusion model
    cmd = ["bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec,
           "--dwi-mask", nodif_brain, "--dir=%s" % phase_enc_dir,
           "--threads=%i" % bdp_nthread]
    subprocess.check_call(cmd)

    # Path to files of interest, created by BrainSuite bdp.sh
    dwi_wo_susceptibility = os.path.join(
        outdir, "t1_brain.dwi.RAS.correct.nii.gz")

    ###############
    # Quality check: create snapshots to visually assert the registration
    # quality

    if qc_dir is None:
        qc_dir = outdir

    # The snapshots won't contain all slices, half of them
    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Path to registered T1
    t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz")

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(qc_dir, "t1_with_nodif_edges.png")
    plot_image(t1_to_dif,
               edge_file=nodif_brain,
               snap_file=t1_with_nodif_edges_png,
               name="T1 in diffusion + edges of nodif",
               cut_coords=nb_slices_in_z - 2)

    # Second png: nodif with edges of T1 registered in diffusion
    nodif_with_t1_edges_png = os.path.join(qc_dir, "nodif_with_t1_edges.png")
    plot_image(nodif_brain,
               edge_file=t1_to_dif,
               snap_file=nodif_with_t1_edges_png,
               name="nodif + edges of registered T1",
               cut_coords=nb_slices_in_z - 2)

    return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir,
                                 dwi,
                                 bval,
                                 bvec,
                                 phase_enc_dir,
                                 subject_id,
                                 subjects_dir=None,
                                 invertX=True,
                                 invertY=False,
                                 invertZ=False,
                                 delete_steps=False):
    """
    Function that runs all preprocessing steps using Connectomist but
    with BrainSuite for the correction of susceptibility distortions.

    Parameters
    ----------
    outdir: str
        Path to directory where all the preprocessing will be done.
    dwi: str
        path to input diffusion-weighted Nifti data.
    bval: str
        Path to the Nifti's associated .bval file.
    bvec: str
        Ppath to Nifti's associated .bval file.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subject_id: str
        Subject identifier used in Freesurfer.
    subjects_dir: Str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    invertX: bool, default True
        If True invert x-axis in diffusion model.
    invertY: bool, default False
        Same as invertX but for y-axis.
    invertZ: bool, default False
        Same as invertX but for z-axis.
    delete_steps: bool
        If True remove all intermediate files and directories at the end of
        preprocessing, to keep only selected files:
        - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz

    Returns
    -------
    outdir: str,
        Path to directory with the preprocessed files.

    <unit>
        <output name="preproc_dwi"  type="File"      />
        <output name="preproc_bval" type="File"      />
        <output name="preproc_bvec" type="File"      />

        <input name="outdir"        type="Directory" />
        <input name="dwi"           type="File"      />
        <input name="bval"          type="File"      />
        <input name="bvec"          type="File"      />
        <input name="phase_enc_dir" type="Str"       />
        <input name="subject_id"    type="Str"       />
        <input name="subjects_dir"  type="Str"       />
        <input name="invertX"       type="Bool"      />
        <input name="invertY"       type="Bool"      />
        <input name="invertZ"       type="Bool"      />
        <input name="delete_steps"  type="Bool"      />
    </unit>
    """

    # Step 0 - Initialization

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Raise an Exception if BrainsuiteCheck is not installed
    check_brainsuite_installation()

    # Create the preprocessing output directory if not existing
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Step 1 - Import files to Connectomist and choose q-space model
    raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model")
    # The manufacturer option is unused (use brainsuite for susceptibility
    # correction) but required
    dwi_data_import_and_qspace_sampling(raw_dwi_dir,
                                        dwi=dwi,
                                        bval=bval,
                                        bvec=bvec,
                                        manufacturer="Siemens",
                                        invertX=invertX,
                                        invertY=invertY,
                                        invertZ=invertZ,
                                        subject_id=subject_id)

    # Step 2 - Create a brain mask
    rough_mask_dir = os.path.join(outdir, "02-Rough_mask")
    dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir)

    # Step 3 - Detect and correct outlying diffusion slices
    outliers_dir = os.path.join(outdir, "03-Outliers")
    dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir)

    # Export outliers.py
    path_outliers_py = os.path.join(outliers_dir, "outliers.py")
    shutil.copy(path_outliers_py, outdir)

    # Step 4 - Eddy current and motion correction
    eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion")
    dwi_eddy_current_and_motion_correction(eddy_motion_dir, raw_dwi_dir,
                                           rough_mask_dir, outliers_dir)

    # Step 5 - Convert Connectomist result to Nifti with bval/bvec
    dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir,
                                                          filename="dwi_ecc")

    # Step 6 - Susceptibility correction using BrainSuite
    brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite")
    if not os.path.isdir(brainsuite_dir):
        os.mkdir(brainsuite_dir)

    dwi_wo_susceptibility, bval, bvec = \
        brainsuite_susceptibility_correction(outdir=brainsuite_dir,
                                             dwi=dwi,
                                             bval=bval,
                                             bvec=bvec,
                                             phase_enc_dir=phase_enc_dir,
                                             subject_id=subject_id,
                                             subjects_dir=subjects_dir,
                                             qc_dir=outdir)

    # Step 7 - move corrected diffusion to outdir
    dwi_preproc = os.path.join(outdir, "dwi.nii.gz")
    bval_preproc = os.path.join(outdir, "dwi.bval")
    bvec_preproc = os.path.join(outdir, "dwi.bvec")
    shutil.copyfile(dwi_wo_susceptibility, dwi_preproc)
    shutil.copyfile(bval, bval_preproc)
    shutil.copyfile(bvec, bvec_preproc)

    # Step 8 - Create a T2 brain mask of preprocessed DWI data
    bet2_prefix = os.path.join(outdir, "nodif_brain")
    nodif_brain = os.path.join(bet2_prefix + ".nii.gz")
    nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz")
    bet2(dwi, bet2_prefix, f=0.25, m=True)

    # Step 9 - clean intermediate directories if requested
    if delete_steps:
        intermediate_directories = [
            raw_dwi_dir, rough_mask_dir, outliers_dir, eddy_motion_dir,
            brainsuite_dir
        ]
        for directory in intermediate_directories:
            shutil.rmtree(directory)

    return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain,
            nodif_brain_mask)
def complete_preproc_wo_fieldmap(outdir,
                                 dwi,
                                 bval,
                                 bvec,
                                 phase_enc_dir,
                                 subject_id,
                                 subjects_dir=None,
                                 invertX=True,
                                 invertY=False,
                                 invertZ=False,
                                 delete_steps=False):
    """
    Function that runs all preprocessing steps using Connectomist but
    with BrainSuite for the correction of susceptibility distortions.

    Parameters
    ----------
    outdir: str
        Path to directory where all the preprocessing will be done.
    dwi: str
        path to input diffusion-weighted Nifti data.
    bval: str
        Path to the Nifti's associated .bval file.
    bvec: str
        Ppath to Nifti's associated .bval file.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subject_id: str
        Subject identifier used in Freesurfer.
    subjects_dir: Str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    invertX: bool, default True
        If True invert x-axis in diffusion model.
    invertY: bool, default False
        Same as invertX but for y-axis.
    invertZ: bool, default False
        Same as invertX but for z-axis.
    delete_steps: bool
        If True remove all intermediate files and directories at the end of
        preprocessing, to keep only selected files:
        - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz

    Returns
    -------
    outdir: str,
        Path to directory with the preprocessed files.

    <unit>
        <output name="preproc_dwi"  type="File"      />
        <output name="preproc_bval" type="File"      />
        <output name="preproc_bvec" type="File"      />

        <input name="outdir"        type="Directory" />
        <input name="dwi"           type="File"      />
        <input name="bval"          type="File"      />
        <input name="bvec"          type="File"      />
        <input name="phase_enc_dir" type="Str"       />
        <input name="subject_id"    type="Str"       />
        <input name="subjects_dir"  type="Str"       />
        <input name="invertX"       type="Bool"      />
        <input name="invertY"       type="Bool"      />
        <input name="invertZ"       type="Bool"      />
        <input name="delete_steps"  type="Bool"      />
    </unit>
    """

    # Step 0 - Initialization

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Raise an Exception if BrainsuiteCheck is not installed
    check_brainsuite_installation()

    # Create the preprocessing output directory if not existing
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Step 1 - Import files to Connectomist and choose q-space model
    raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model")
    # The manufacturer option is unused (use brainsuite for susceptibility
    # correction) but required
    dwi_data_import_and_qspace_sampling(raw_dwi_dir,
                                        dwi=dwi,
                                        bval=bval,
                                        bvec=bvec,
                                        manufacturer="Siemens",
                                        invertX=invertX,
                                        invertY=invertY,
                                        invertZ=invertZ,
                                        subject_id=subject_id)

    # Step 2 - Create a brain mask
    rough_mask_dir = os.path.join(outdir, "02-Rough_mask")
    dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir)

    # Step 3 - Detect and correct outlying diffusion slices
    outliers_dir = os.path.join(outdir, "03-Outliers")
    dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir)

    # Export outliers.py
    path_outliers_py = os.path.join(outliers_dir, "outliers.py")
    shutil.copy(path_outliers_py, outdir)

    # Step 4 - Eddy current and motion correction
    eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion")
    dwi_eddy_current_and_motion_correction(eddy_motion_dir,
                                           raw_dwi_dir,
                                           rough_mask_dir,
                                           outliers_dir)

    # Step 5 - Convert Connectomist result to Nifti with bval/bvec
    dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir,
                                                          filename="dwi_ecc")

    # Step 6 - Susceptibility correction using BrainSuite
    brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite")
    if not os.path.isdir(brainsuite_dir):
        os.mkdir(brainsuite_dir)

    dwi_wo_susceptibility, bval, bvec = \
        brainsuite_susceptibility_correction(outdir=brainsuite_dir,
                                             dwi=dwi,
                                             bval=bval,
                                             bvec=bvec,
                                             phase_enc_dir=phase_enc_dir,
                                             subject_id=subject_id,
                                             subjects_dir=subjects_dir,
                                             qc_dir=outdir)

    # Step 7 - move corrected diffusion to outdir
    dwi_preproc = os.path.join(outdir, "dwi.nii.gz")
    bval_preproc = os.path.join(outdir, "dwi.bval")
    bvec_preproc = os.path.join(outdir, "dwi.bvec")
    shutil.copyfile(dwi_wo_susceptibility, dwi_preproc)
    shutil.copyfile(bval, bval_preproc)
    shutil.copyfile(bvec, bvec_preproc)

    # Step 8 - Create a T2 brain mask of preprocessed DWI data
    bet2_prefix = os.path.join(outdir, "nodif_brain")
    nodif_brain = os.path.join(bet2_prefix + ".nii.gz")
    nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz")
    bet2(dwi, bet2_prefix, f=0.25, m=True)

    # Step 9 - clean intermediate directories if requested
    if delete_steps:
        intermediate_directories = [raw_dwi_dir,
                                    rough_mask_dir,
                                    outliers_dir,
                                    eddy_motion_dir,
                                    brainsuite_dir]
        for directory in intermediate_directories:
            shutil.rmtree(directory)

    return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain,
            nodif_brain_mask)