コード例 #1
0
ファイル: translate.py プロジェクト: vittalkorann/bidskit
def fmap_echotimes(src_phase_json_fname):
    """
    Extract TE1 and TE2 from mag and phase MEGE fieldmap pairs

    :param src_phase_json_fname: str
    :return:
    """

    # Init returned TEs
    te1, te2 = 0.0, 0.0

    if os.path.isfile(src_phase_json_fname):

        # Read phase image metadata
        phase_dict = bio.read_json(src_phase_json_fname)

        # Populate series info dictionary from dcm2niix output filename
        info = bio.parse_dcm2niix_fname(src_phase_json_fname)

        # Siemens: Magnitude 1 series number is one less than phasediff series number
        mag1_ser_no = str(int(info['SerNo']) - 1)

        # Construct dcm2niix mag1 JSON filename
        # Requires dicm2niix v1.0.20180404 or later for echo number suffix '_e1'
        src_mag1_json_fname = info['SubjName'] + '--' + info['SerDesc'] + '--' + \
            info['SeqName'] + '--' + mag1_ser_no + '_e1.json'
        src_mag1_json_path = os.path.join(
            os.path.dirname(src_phase_json_fname), src_mag1_json_fname)

        # Read mag1 metadata
        mag1_dict = bio.read_json(src_mag1_json_path)

        # Add te1 key and rename TE2 key
        if mag1_dict:
            te1 = mag1_dict['EchoTime']
            te2 = phase_dict['EchoTime']
        else:
            print(
                '*** Could not determine echo times multiecho fieldmap - using 0.0 '
            )

    else:

        print('* Fieldmap phase difference sidecar not found : ' +
              src_phase_json_fname)

    return te1, te2
コード例 #2
0
ファイル: translate.py プロジェクト: vittalkorann/bidskit
def auto_run_no(file_list, prot_dict):
    """
    Search for duplicate series names in dcm2niix output file list
    Return inferred run numbers accounting for duplication and multiple recons from single acquisition

    NOTES:
    - Multiple recons generated by single acquisition (eg multiecho fieldmaps, localizers, etc) are
      handled through the dcm2niix extensions (_e1, _ph, _i00001, etc).
    - Series number resets following subject re-landmarking make the SerNo useful only for
      determining series uniqueness and not for ordering or run numbering.

    :param file_list: list of str
        Nifti file name list
    :param prot_dict: dictionary
        Protocol translation dictionary
    :return: run_num, array of int
    """

    # Construct list of series descriptions and original numbers from file names
    desc_list = []

    for fname in file_list:

        # Parse dcm2niix filename into relevant keys, including suffix
        info = bio.parse_dcm2niix_fname(fname)
        _, bids_suffix, _ = prot_dict[info['SerDesc']]

        # Construct a unique series description using multirecon suffix
        ser_suffix = bids_suffix + '_' + info['Suffix']

        # Add to list
        desc_list.append(ser_suffix)

    # Find unique ser_desc entries using sets
    unique_descs = set(desc_list)

    run_no = np.zeros(len(file_list))

    for unique_desc in unique_descs:
        run_count = 1
        for i, desc in enumerate(desc_list):
            if desc == unique_desc:
                run_no[i] = run_count
                run_count += 1

    return run_no
コード例 #3
0
ファイル: translate.py プロジェクト: jmtyszka/bidskit
def auto_run_no(file_list, prot_dict):
    """
    Search for duplicate series names in dcm2niix output file list
    Return inferred run numbers accounting for duplication and multiple recons from single acquisition

    NOTES:
    - Multiple recons generated by single acquisition (eg multiecho fieldmaps, localizers, etc) are
      handled through the dcm2niix extensions (_e1, _ph, _i00001, etc).
    - Series number resets following subject re-landmarking make the SerNo useful only for
      determining series uniqueness and not for ordering or run numbering.

    :param file_list: list of str
        Nifti file name list
    :param prot_dict: dictionary
        Protocol translation dictionary
    :return: run_num, array of int
    """

    # Construct list of series descriptions and original numbers from file names
    desc_list = []

    for fname in file_list:

        # Parse dcm2niix filename into relevant keys, including suffix
        info = bio.parse_dcm2niix_fname(fname)
        _, bids_suffix, _ = prot_dict[info['SerDesc']]
        
        # Construct a unique series description using multirecon suffix
        ser_suffix = bids_suffix + '_' + info['Suffix']

        # Add to list
        desc_list.append(ser_suffix)

    # Find unique ser_desc entries using sets
    unique_descs = set(desc_list)

    run_no = np.zeros(len(file_list))

    for unique_desc in unique_descs:
        run_count = 1
        for i, desc in enumerate(desc_list):
            if desc == unique_desc:
                run_no[i] = run_count
                run_count += 1

    return run_no
コード例 #4
0
ファイル: translate.py プロジェクト: jmtyszka/bidskit
def fmap_echotimes(src_phase_json_fname):
    """
    Extract TE1 and TE2 from mag and phase MEGE fieldmap pairs

    :param src_phase_json_fname: str
    :return:
    """

    # Init returned TEs
    te1, te2 = 0.0, 0.0

    if os.path.isfile(src_phase_json_fname):

        # Read phase image metadata
        phase_dict = bio.read_json(src_phase_json_fname)

        # Populate series info dictionary from dcm2niix output filename
        info = bio.parse_dcm2niix_fname(src_phase_json_fname)

        # Siemens: Magnitude 1 series number is one less than phasediff series number
        mag1_ser_no = str(int(info['SerNo']) - 1)

        # Construct dcm2niix mag1 JSON filename
        # Requires dicm2niix v1.0.20180404 or later for echo number suffix '_e1'
        src_mag1_json_fname = info['SubjName'] + '--' + info['SerDesc'] + '--' + \
            info['SeqName'] + '--' + mag1_ser_no + '_e1.json'
        src_mag1_json_path = os.path.join(os.path.dirname(src_phase_json_fname), src_mag1_json_fname)

        # Read mag1 metadata
        mag1_dict = bio.read_json(src_mag1_json_path)

        # Add te1 key and rename TE2 key
        if mag1_dict:
            te1 = mag1_dict['EchoTime']
            te2 = phase_dict['EchoTime']
        else:
            print('*** Could not determine echo times multiecho fieldmap - using 0.0 ')

    else:

        print('* Fieldmap phase difference sidecar not found : ' + src_phase_json_fname)

    return te1, te2
コード例 #5
0
def organize_series(conv_dir,
                    first_pass,
                    prot_dict,
                    src_dir,
                    sid,
                    ses,
                    clean_conv_dir,
                    overwrite=False):
    """
    Organize dcm2niix output into BIDS subject/session directory

    :param conv_dir: string
        Working conversion directory
    :param first_pass: boolean
        Flag for first pass conversion
    :param prot_dict: dictionary
        Protocol translation dictionary
    :param src_dir: string
        BIDS source output subj or subj/session directory
    :param sid: string
        subject ID
    :param ses: string
        session name or number
    :param clean_conv_dir: bool
        clean up conversion directory
    :param overwrite: bool
        overwrite flag
    :return:
    """

    # Flag for working conversion directory cleanup
    do_cleanup = clean_conv_dir

    # Proceed if conversion directory exists
    if os.path.isdir(conv_dir):

        # Get Nifti file list ordered by acquisition time
        nii_list, json_list, acq_times = btr.ordered_file_list(conv_dir)

        # Infer run numbers accounting for duplicates.
        # Only used if run-* not present in translator BIDS filename stub
        if not first_pass:
            run_no = btr.auto_run_no(nii_list, prot_dict)

        # Loop over all Nifti files (*.nii, *.nii.gz) for this subject
        for fc, src_nii_fname in enumerate(nii_list):

            # Parse image filename into fields
            info = bio.parse_dcm2niix_fname(src_nii_fname)

            # Check if we're creating new protocol dictionary
            if first_pass:

                print('  Adding protocol %s to dictionary template' %
                      info['SerDesc'])

                # Add current protocol to protocol dictionary
                # Use default EXCLUDE_* values which can be changed (or not) by the user
                prot_dict[info['SerDesc']] = [
                    "EXCLUDE_BIDS_Directory", "EXCLUDE_BIDS_Name", "UNASSIGNED"
                ]

            else:

                # JSON sidecar for this image
                src_json_fname = json_list[fc]

                # Warn if not found and continue
                if not os.path.isfile(src_json_fname):
                    print('* WARNING: JSON sidecar %s not found' %
                          src_json_fname)
                    continue

                if info['SerDesc'] in prot_dict.keys():

                    if prot_dict[info['SerDesc']][0].startswith('EXCLUDE'):

                        # Skip excluded protocols
                        print('* Excluding protocol ' + str(info['SerDesc']))

                    else:

                        print('  Organizing ' + str(info['SerDesc']))

                        # Use protocol dictionary to determine purpose folder, BIDS filename suffix and fmap linking
                        bids_purpose, bids_suffix, bids_intendedfor = prot_dict[
                            info['SerDesc']]

                        # Safely add run-* key to BIDS suffix
                        bids_suffix = btr.add_run_number(
                            bids_suffix, run_no[fc])

                        # Assume the IntendedFor field should aslo have a run- added
                        prot_dict = btr.add_intended_run(
                            prot_dict, info, run_no[fc])

                        # Create BIDS purpose directory
                        bids_purpose_dir = os.path.join(src_dir, bids_purpose)
                        bio.safe_mkdir(bids_purpose_dir)

                        # Complete BIDS filenames for image and sidecar
                        if ses:
                            bids_prefix = 'sub-' + sid + '_ses-' + ses + '_'
                        else:
                            bids_prefix = 'sub-' + sid + '_'

                        # Construct BIDS source Nifti and JSON filenames
                        bids_nii_fname = os.path.join(
                            bids_purpose_dir,
                            bids_prefix + bids_suffix + '.nii.gz')
                        bids_json_fname = bids_nii_fname.replace(
                            '.nii.gz', '.json')

                        # Add prefix and suffix to IntendedFor values
                        if 'UNASSIGNED' not in bids_intendedfor:
                            if isinstance(bids_intendedfor, str):
                                # Single linked image
                                bids_intendedfor = btr.build_intendedfor(
                                    sid, ses, bids_intendedfor)
                            else:
                                # Loop over all linked images
                                for ifc, ifstr in enumerate(bids_intendedfor):
                                    # Avoid multiple substitutions
                                    if '.nii.gz' not in ifstr:
                                        bids_intendedfor[
                                            ifc] = btr.build_intendedfor(
                                                sid, ses, ifstr)

                        # Special handling for specific purposes (anat, func, fmap, etc)
                        # This function populates BIDS structure with the image and adjusted sidecar
                        btr.purpose_handling(bids_purpose, bids_intendedfor,
                                             info['SeqName'], src_nii_fname,
                                             src_json_fname, bids_nii_fname,
                                             bids_json_fname, overwrite)
                else:

                    # Skip protocols not in the dictionary
                    print('* Protocol ' + str(info['SerDesc']) +
                          ' is not in the dictionary, did not convert.')

        if not first_pass:

            # Optional working directory cleanup after Pass 2
            if do_cleanup:
                print('  Cleaning up temporary files')
                shutil.rmtree(conv_dir)
            else:
                print('  Preserving conversion directory')
コード例 #6
0
ファイル: translate.py プロジェクト: vittalkorann/bidskit
def purpose_handling(bids_purpose,
                     bids_intendedfor,
                     seq_name,
                     work_nii_fname,
                     work_json_fname,
                     bids_nii_fname,
                     bids_json_fname,
                     overwrite=False):
    """
    Special handling for each image purpose (func, anat, fmap, dwi, etc)

    :param bids_purpose: str
    :param bids_intendedfor: str
    :param seq_name: str
    :param work_nii_fname: str
    :param work_json_fname: str
    :param bids_nii_fname: str
    :param bids_json_fname: str
    :param overwrite: bool
    :return:
    """

    # Init DWI sidecars
    work_bval_fname = []
    work_bvec_fname = []
    bids_bval_fname = []
    bids_bvec_fname = []

    # Load the JSON sidecar
    bids_info = bio.read_json(work_json_fname)

    if bids_purpose == 'func':

        if seq_name == 'EP':

            print('    EPI detected')
            create_events_template(bids_nii_fname, overwrite)

            # Add taskname to BIDS JSON sidecar
            bids_keys = bio.parse_bids_fname(bids_nii_fname)
            if 'task' in bids_keys:
                bids_info['TaskName'] = bids_keys['task']
            else:
                bids_info['TaskName'] = 'unknown'

    elif bids_purpose == 'fmap':

        # Add IntendedFor field if requested through protocol translator
        if 'UNASSIGNED' not in bids_intendedfor:
            bids_info['IntendedFor'] = bids_intendedfor

        # Check for MEGE vs SE-EPI fieldmap images
        # MEGE will have a 'GR' sequence, SE-EPI will have 'EP'

        print('    Identifying fieldmap image type')

        if seq_name == 'GR':

            print('    GRE detected')
            print('    Identifying magnitude and phase images')

            # Siemens: Dual gradient echo fieldmaps reconstruct to three series
            # (Requires dcm2nixx v1.0.20180404 or later for echo number suffix)
            # *--GR--<serno>_e1.<ext> : magnitude image from echo 1
            # *--GR--<serno>_e2.<ext> : magnitude image from echo 2
            # *--GR--<serno+1>_ph.<ext> : inter-echo phase difference

            # Pull dcm2niix filename info
            work_info = bio.parse_dcm2niix_fname(work_nii_fname)

            if 'e1' in work_info['Suffix']:

                print('    Echo 1 magnitude detected')

                # Replace existing contrast suffix (if any) with '_magnitude1'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude1')
                bids_json_fname = []  # Do not copy sidecar

            elif 'e2' in work_info['Suffix']:

                print('    Echo 2 magnitude detected')

                # Replace existing contrast suffix (if any) with '_magnitude1'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude2')
                bids_json_fname = []  # Do not copy sidecar

            elif 'ph' in work_info['Suffix']:

                print('    Interecho phase difference detected')

                # Replace existing contrast suffix (if any) with '_phasediff'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'phasediff')
                bids_json_fname = replace_contrast(bids_json_fname,
                                                   'phasediff')

                # Extract TE1 and TE2 from mag and phase JSON sidecars
                te1, te2 = fmap_echotimes(work_json_fname)
                bids_info['EchoTime1'] = te1
                bids_info['EchoTime2'] = te2

            else:

                print('*   Magnitude or phase image not found - skipping')
                bids_nii_fname = []
                bids_json_fname = []

        elif seq_name == 'EP':

            print('    EPI detected')

        else:

            print('    Unrecognized fieldmap detected')
            print('    Simply copying image and sidecar to fmap directory')

    elif bids_purpose == 'anat':

        if seq_name == 'GR_IR':

            print(
                '    IR-prepared GRE detected - likely T1w MP-RAGE or equivalent'
            )

        elif seq_name == 'SE':

            print('    Spin echo detected - likely T1w or T2w anatomic image')

        elif seq_name == 'GR':

            print('    Gradient echo detected')

    elif bids_purpose == 'dwi':

        # Fill DWI bval and bvec working and source filenames
        # Non-empty filenames trigger the copy below
        work_bval_fname = str(work_json_fname.replace('.json', '.bval'))
        bids_bval_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bval'))
        work_bvec_fname = str(work_json_fname.replace('.json', '.bvec'))
        bids_bvec_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bvec'))

    # Populate BIDS source directory with Nifti images, JSON and DWI sidecars
    print('  Populating BIDS source directory')

    if bids_nii_fname:
        bio.safe_copy(work_nii_fname, str(bids_nii_fname), overwrite)

    if bids_json_fname:
        bio.write_json(bids_json_fname, bids_info, overwrite)

    if bids_bval_fname:
        bio.safe_copy(work_bval_fname, bids_bval_fname, overwrite)

    if bids_bvec_fname:
        bio.safe_copy(work_bvec_fname, bids_bvec_fname, overwrite)
コード例 #7
0
ファイル: organize.py プロジェクト: jmtyszka/bidskit
def organize_series(conv_dir, first_pass, prot_dict, src_dir, sid, ses, clean_conv_dir, overwrite=False):
    """
    Organize dcm2niix output into BIDS subject/session directory

    :param conv_dir: string
        Working conversion directory
    :param first_pass: boolean
        Flag for first pass conversion
    :param prot_dict: dictionary
        Protocol translation dictionary
    :param src_dir: string
        BIDS source output subj or subj/session directory
    :param sid: string
        subject ID
    :param ses: string
        session name or number
    :param clean_conv_dir: bool
        clean up conversion directory
    :param overwrite: bool
        overwrite flag
    :return:
    """

    # Flag for working conversion directory cleanup
    do_cleanup = clean_conv_dir

    # Proceed if conversion directory exists
    if os.path.isdir(conv_dir):

        # Get Nifti file list ordered by acquisition time
        nii_list, json_list, acq_times = btr.ordered_file_list(conv_dir)

        # Infer run numbers accounting for duplicates.
        # Only used if run-* not present in translator BIDS filename stub
        if not first_pass:
            run_no = btr.auto_run_no(nii_list, prot_dict)

        # Loop over all Nifti files (*.nii, *.nii.gz) for this subject
        for fc, src_nii_fname in enumerate(nii_list):

            # Parse image filename into fields
            info = bio.parse_dcm2niix_fname(src_nii_fname)

            # Check if we're creating new protocol dictionary
            if first_pass:

                print('  Adding protocol %s to dictionary template' % info['SerDesc'])

                # Add current protocol to protocol dictionary
                # Use default EXCLUDE_* values which can be changed (or not) by the user
                prot_dict[info['SerDesc']] = ["EXCLUDE_BIDS_Directory", "EXCLUDE_BIDS_Name", "UNASSIGNED"]

            else:

                # JSON sidecar for this image
                src_json_fname = json_list[fc]

                # Warn if not found and continue
                if not os.path.isfile(src_json_fname):
                    print('* WARNING: JSON sidecar %s not found' % src_json_fname)
                    continue

                if info['SerDesc'] in prot_dict.keys():

                    if prot_dict[info['SerDesc']][0].startswith('EXCLUDE'):

                        # Skip excluded protocols
                        print('* Excluding protocol ' + str(info['SerDesc']))

                    else:

                        print('  Organizing ' + str(info['SerDesc']))

                        # Use protocol dictionary to determine purpose folder, BIDS filename suffix and fmap linking
                        bids_purpose, bids_suffix, bids_intendedfor = prot_dict[info['SerDesc']]

                        # Safely add run-* key to BIDS suffix
                        bids_suffix = btr.add_run_number(bids_suffix, run_no[fc])

                        # Assume the IntendedFor field should aslo have a run- added
                        prot_dict = btr.add_intended_run(prot_dict, info, run_no[fc])

                        # Create BIDS purpose directory
                        bids_purpose_dir = os.path.join(src_dir, bids_purpose)
                        bio.safe_mkdir(bids_purpose_dir)

                        # Complete BIDS filenames for image and sidecar
                        if ses:
                            bids_prefix = 'sub-' + sid + '_ses-' + ses + '_'
                        else:
                            bids_prefix = 'sub-' + sid + '_'

                        # Construct BIDS source Nifti and JSON filenames
                        bids_nii_fname = os.path.join(bids_purpose_dir, bids_prefix + bids_suffix + '.nii.gz')
                        bids_json_fname = bids_nii_fname.replace('.nii.gz', '.json')

                        # Add prefix and suffix to IntendedFor values
                        if 'UNASSIGNED' not in bids_intendedfor:
                            if isinstance(bids_intendedfor, str):
                                # Single linked image
                                bids_intendedfor = btr.build_intendedfor(sid, ses, bids_intendedfor)
                            else:
                                # Loop over all linked images
                                for ifc, ifstr in enumerate(bids_intendedfor):
                                    # Avoid multiple substitutions
                                    if '.nii.gz' not in ifstr:
                                        bids_intendedfor[ifc] = btr.build_intendedfor(sid, ses, ifstr)

                        # Special handling for specific purposes (anat, func, fmap, etc)
                        # This function populates BIDS structure with the image and adjusted sidecar
                        btr.purpose_handling(bids_purpose, bids_intendedfor, info['SeqName'],
                                             src_nii_fname, src_json_fname,
                                             bids_nii_fname, bids_json_fname,
                                             overwrite)
                else:

                    # Skip protocols not in the dictionary
                    print('* Protocol ' + str(info['SerDesc']) + ' is not in the dictionary, did not convert.')

        if not first_pass:

            # Optional working directory cleanup after Pass 2
            if do_cleanup:
                print('  Cleaning up temporary files')
                shutil.rmtree(conv_dir)
            else:
                print('  Preserving conversion directory')
コード例 #8
0
ファイル: translate.py プロジェクト: jmtyszka/bidskit
def purpose_handling(bids_purpose, bids_intendedfor, seq_name,
                     work_nii_fname, work_json_fname, bids_nii_fname, bids_json_fname,
                     overwrite=False):
    """
    Special handling for each image purpose (func, anat, fmap, dwi, etc)

    :param bids_purpose: str
    :param bids_intendedfor: str
    :param seq_name: str
    :param work_nii_fname: str
    :param work_json_fname: str
    :param bids_nii_fname: str
    :param bids_json_fname: str
    :param overwrite: bool
    :return:
    """

    # Init DWI sidecars
    work_bval_fname = []
    work_bvec_fname = []
    bids_bval_fname = []
    bids_bvec_fname = []

    # Load the JSON sidecar
    bids_info = bio.read_json(work_json_fname)

    if bids_purpose == 'func':

        if seq_name == 'EP':

            print('    EPI detected')
            create_events_template(bids_nii_fname, overwrite)

            # Add taskname to BIDS JSON sidecar
            bids_keys = bio.parse_bids_fname(bids_nii_fname)
            if 'task' in bids_keys:
                bids_info['TaskName'] = bids_keys['task']
            else:
                bids_info['TaskName'] = 'unknown'

    elif bids_purpose == 'fmap':

        # Add IntendedFor field if requested through protocol translator
        if 'UNASSIGNED' not in bids_intendedfor:
            bids_info['IntendedFor'] = bids_intendedfor

        # Check for MEGE vs SE-EPI fieldmap images
        # MEGE will have a 'GR' sequence, SE-EPI will have 'EP'

        print('    Identifying fieldmap image type')

        if seq_name == 'GR':

            print('    GRE detected')
            print('    Identifying magnitude and phase images')

            # Siemens: Dual gradient echo fieldmaps reconstruct to three series
            # (Requires dcm2nixx v1.0.20180404 or later for echo number suffix)
            # *--GR--<serno>_e1.<ext> : magnitude image from echo 1
            # *--GR--<serno>_e2.<ext> : magnitude image from echo 2
            # *--GR--<serno+1>_ph.<ext> : inter-echo phase difference

            # Pull dcm2niix filename info
            work_info = bio.parse_dcm2niix_fname(work_nii_fname)

            if 'e1' in work_info['Suffix']:

                print('    Echo 1 magnitude detected')

                # Replace existing contrast suffix (if any) with '_magnitude1'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude1')
                bids_json_fname = []  # Do not copy sidecar

            elif 'e2' in work_info['Suffix']:

                print('    Echo 2 magnitude detected')

                # Replace existing contrast suffix (if any) with '_magnitude1'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'magnitude2')
                bids_json_fname = []  # Do not copy sidecar

            elif 'ph' in work_info['Suffix']:

                print('    Interecho phase difference detected')

                # Replace existing contrast suffix (if any) with '_phasediff'
                bids_nii_fname = replace_contrast(bids_nii_fname, 'phasediff')
                bids_json_fname = replace_contrast(bids_json_fname, 'phasediff')

                # Extract TE1 and TE2 from mag and phase JSON sidecars
                te1, te2 = fmap_echotimes(work_json_fname)
                bids_info['EchoTime1'] = te1
                bids_info['EchoTime2'] = te2

            else:

                print('*   Magnitude or phase image not found - skipping')
                bids_nii_fname = []
                bids_json_fname = []

        elif seq_name == 'EP':

            print('    EPI detected')

        else:

            print('    Unrecognized fieldmap detected')
            print('    Simply copying image and sidecar to fmap directory')

    elif bids_purpose == 'anat':

        if seq_name == 'GR_IR':

            print('    IR-prepared GRE detected - likely T1w MP-RAGE or equivalent')

        elif seq_name == 'SE':

            print('    Spin echo detected - likely T1w or T2w anatomic image')

        elif seq_name == 'GR':

            print('    Gradient echo detected')

    elif bids_purpose == 'dwi':

        # Fill DWI bval and bvec working and source filenames
        # Non-empty filenames trigger the copy below
        work_bval_fname = str(work_json_fname.replace('.json', '.bval'))
        bids_bval_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bval'))
        work_bvec_fname = str(work_json_fname.replace('.json', '.bvec'))
        bids_bvec_fname = str(bids_json_fname.replace('dwi.json', 'dwi.bvec'))

    # Populate BIDS source directory with Nifti images, JSON and DWI sidecars
    print('  Populating BIDS source directory')

    if bids_nii_fname:
        bio.safe_copy(work_nii_fname, str(bids_nii_fname), overwrite)

    if bids_json_fname:
        bio.write_json(bids_json_fname, bids_info, overwrite)

    if bids_bval_fname:
        bio.safe_copy(work_bval_fname, bids_bval_fname, overwrite)

    if bids_bvec_fname:
        bio.safe_copy(work_bvec_fname, bids_bvec_fname, overwrite)