PennLINC / fw-heudiconv

Heuristic-based Data Curation on Flywheel
BSD 3-Clause "New" or "Revised" License
6 stars 11 forks source link

Blipup DWI PE doesn't output under fmap #86

Closed akelkar26 closed 3 years ago

akelkar26 commented 3 years ago

Hi, I have a question about a unique dataset. I have a dti file (with PE: A>>P) and a blipup file (with PE: R>>L).

I am trying to write the blipup file to the fmap folder (according to documentation about pepolar technique mentioned here under Case 4: Multiple phase encoded directions ("pepolar") https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#case-4-multiple-phase-encoded-directions-pepolar

However, my heuristic file doesn't write the pe_rev file out under fmap and instead writes it as a second acquisition under dwi folder. Am I doing something wrong here?

Here is my heuristic file:

!/usr/bin/env python

import os import re

def create_key(template, outtype=('nii.gz',), annotation_classes=None): if template is None or not template: raise ValueError('Template must be a valid format string') return template, outtype, annotation_classes

Note: All files should be in nifti format before using this script

Struct

t1w = createkey( 'sub-{subject}/{session}/anat/sub-{subject}{session}_T1w')

dwi

dwiseq1 = createkey('sub-{subject}/{session}/dwi/sub-{subject}{session}_run-1_dwi')

dwi = createkey( 'sub-{subject}/{session}/dwi/sub-{subject}{session}_acq-multiband_dwi')

rest

rest1 = createkey( 'sub-{subject}/{session}/func/sub-{subject}{session}_task-rest_run-1_bold')

field maps

fmap_run1_ph = createkey( 'sub-{subject}/{session}/fmap/sub-{subject}{session}_run-1_phasediff') fmap_run1_mag = createkey( 'sub-{subject}/{session}/fmap/sub-{subject}{session}_run-1_magnitude{item}')

pe_rev = createkey( 'sub-{subject}/{session}/fmap/sub-{subject}{session}_acq-multiband_dir-0_epi')

def infotodict(seqinfo): """Heuristic evaluator for determining which runs belong where allowed template fields - follow python string module: item: index within category subject: participant id seqitem: run number during scanning subindex: sub index within group session: session id """

info = {
    # baseline
    t1w: [],
    # field map
    fmap_run1_ph: [], fmap_run1_mag: [], pe_rev: [],
    #tms session rest scans
    rest1: [],
    # dwi
    dwi: [],
}

# sometimes patients struggle with a task the first time around (or something
# else goes wrong and often some tasks are repeated. This function accomodates
# the variable number of task runs
def get_both_series(key1, key2, s):
     if len(info[key1]) == 0:
         info[key1].append(s.series_id)
     else:
         info[key2].append(s.series_id)

def get_multi_b0mag(key1, key2, s):
     if len(info[key1]) < 2:
         info[key1].append(s.series_id)
     else:
         info[key2].append(s.series_id)

# this doesn't need to be a function but using it anyway for aesthetic symmetry
# with above function
def get_series(key, s):
        info[key].append(s.series_id)

for s in seqinfo:
    protocol = s.protocol_name.lower()

    fileCount = s.total_files_till_now

    # Baseline Anatomicals
    if "t1_mpr_sag_mprage" in protocol:
        get_series(t1w, s)

    # Diffusion tensor image
    elif "dti" in protocol and not s.is_derived:
         get_series(dwi, s)

    #Resting task scans (Need to change according to timepoint (date))
    elif "restingbold_mb6_1200" in protocol:
        get_series(rest1, s) #rest2, s)

    elif "b0map" in protocol and "M" in s.image_type:
        #get_b0mag(fmap_run1_mag, s)
        info[fmap_run1_mag].append(s.series_id)
    elif "b0map" in protocol and "P" in s.image_type:
        #get_series(fmap_run1_ph, s)
        info[fmap_run1_ph].append(s.series_id)

    # Diffusion Spin Echo EPI scan
    elif "dti_blipup" in protocol:
        get_series(pe_rev, s)
return info

MetadataExtras = { fmap_run1_ph: { "EchoTime1": 0.00412, "EchoTime2": 0.00658 }, pe_rev: { "PhaseEncodingDirection": "i", "TotalReadoutTime": 0.06095, } }

R>>L phase encoding direction

From scanner protocol, Echo spacing = 0.53ms, EPI factor = 116

Total readout time = Echo spacing x 0.001 x (EPI factor-1)

IntendedFor = { fmap_run1mag: ['{session}/func/sub-{subject}{session}_task-rest_run-1_bold.nii.gz'], fmap_run1ph: ['{session}/func/sub-{subject}{session}_task-rest_run-1_bold.nii.gz'], perev: ['{session}/dwi/sub-{subject}{session}_acq-multiband_dwi.nii.gz'], }

Function to swap out the '.' in the subIDs as they are uploaded.

def ReplaceSubject(subj_label):

p = re.compile('\.SC\.1\.')

return str(p.sub("", subj_label))

Your help will be greatly appreciated. Thank you in advance.

akelkar26 commented 3 years ago

Hi,

Good morning. I am just reaching out to ask if you had any insight on this issue? Any feedback would be super helpful. I am kind of stuck on this now. Thank you in advance.

TinasheMTapera commented 3 years ago

Hi @akelkar26,

Take a look at this step in your heuristic:

    # Diffusion tensor image
    elif "dti" in protocol and not s.is_derived:
         get_series(dwi, s)

Can you be sure that your epi files have this condition s.is_derived? Because later you have

    # Diffusion Spin Echo EPI scan
    elif "dti_blipup" in protocol:
        get_series(pe_rev, s)

These two conditions can both be met if your heuristic isn't strict enough (the EPI protocol name has both dti and dti_blipup in its string). In other words, the EPI acquisition has files that are definitely being met by both conditions, but because your dti assignment comes first, EPI files are being assigned there.

Try putting the EPI condition above your diffusion condition to see what I mean.

akelkar26 commented 3 years ago

Hi @TinasheMTapera thank you so much for the feedback. I realized I don't need the s.is_derived so I removed it.

I also put the EPI condition above the diffusion condition and the DWI blipup PE file was output under the fmap folder successfully.

Thank you so much for the insight. It helped me solve the issue.

TinasheMTapera commented 3 years ago

Not a problem at all, friend!