Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some info missing from func and fmap .json files #27

Closed
ccharpen opened this issue Mar 2, 2018 · 4 comments
Closed

Some info missing from func and fmap .json files #27

ccharpen opened this issue Mar 2, 2018 · 4 comments
Assignees

Comments

@ccharpen
Copy link

ccharpen commented Mar 2, 2018

Here are some info that I noticed are not in the final .json file associated with each field map and each functional run:

  • the "IntendedFor" needs to include the full directory of where the corresponding functional run(s) associated with that field map are save: e.g. "IntendedFor":"func/sub-005_task-ObsLearn_run-01_bold.nii.gz" or "IntendedFor":"func/ses-1/sub-005_task-ObsLearn_run-01_bold.nii.gz". Right now having only "IntendedFor":"task-ObsLearn_run-01_bold.nii.gz" will appear as an error in the bids validator (and I am assuming fmriprep won't run). I guess this could be changed when updating the protocol translator, or during the second pass conversion.
  • the "TotalReadoutTime" is also not added, both for to the func and fmap .json. I understand that this can be different depending on the scanner and/or sequence, but it would be nice if there was a way to incorporate it?
  • in my case, I also wanted the "MultibandAccelerationFactor" to be included.

I wrote the following python script that all my subjects and all my run and adds all this information - in case that helps for fixing the issue within the dcm2bids.py scripts.

#!/usr/bin/env python
"""
Created on Mon Nov 27 15:50:50 2017
@author: Caroline
"""

import os
import sys
import argparse
import subprocess
import shutil
import json
import dicom
from glob import glob

def main():
    
    bids_dir = os.path.realpath('/home/ccharpen/ObsLearn/rawdata/rawBIDS/')

    for bids_sub_dir in glob(bids_dir + '/sub*/'):
        
        print('Subject Directory: %s' % bids_sub_dir)
        func_dir = os.path.join(bids_sub_dir, 'func')
        fmap_dir = os.path.join(bids_sub_dir, 'fmap')
        
        for run in range(8):
            
            func_run_name = glob(func_dir + '/sub*' + str(run+1) + '_bold.json')[0]
            run_dict = read_json(func_run_name)
            #for functional run .json file, add TotalReadoutTime and MultibandAccelerationFactor
            #those parameters are specific to that protocol - update accordingly
            if 'TotalReadoutTime' not in run_dict.keys():
                run_dict['TotalReadoutTime']=0.0432
            if 'MultibandAccelerationFactor' not in run_dict.keys():
                run_dict['MultibandAccelerationFactor']=4
            write_json(func_run_name,run_dict)
            
            #for field maps, add TotalReadoutTime and 'func/' in front of the "IntendedFor" filename
            fmap_pos_name = glob(fmap_dir + '/sub*-pos_run-0' + str(run+1) + '_epi.json')[0]
            pos_dict = read_json(fmap_pos_name)
            if 'TotalReadoutTime' not in pos_dict.keys():
                pos_dict['TotalReadoutTime']=0.0432
            tmp_pos_name = str(pos_dict['IntendedFor'])
            if 'func/' not in tmp_pos_name:
                new_pos_name = 'func/' + tmp_pos_name
                pos_dict['IntendedFor'] = new_pos_name
            write_json(fmap_pos_name,pos_dict)
    
            fmap_neg_name = glob(fmap_dir + '/sub*-neg_run-0' + str(run+1) + '_epi.json')[0]
            neg_dict = read_json(fmap_neg_name)
            if 'TotalReadoutTime' not in neg_dict.keys():
                neg_dict['TotalReadoutTime']=0.0432
            tmp_neg_name = str(neg_dict['IntendedFor'])
            if 'func/' not in tmp_neg_name:
                new_neg_name = 'func/' + tmp_neg_name
                neg_dict['IntendedFor'] = new_neg_name
            write_json(fmap_neg_name,neg_dict)  
        
    # Clean exit
    sys.exit(0)

def read_json(fname):
    """
    Safely read JSON sidecar file into a dictionary
    :param fname: string
        JSON filename
    :return: dictionary structure
    """

    try:
        fd = open(fname, 'r')
        json_dict = json.load(fd)
        fd.close()
    except:
        print('*** JSON sidecar not found - returning empty dictionary')
        json_dict = dict()

    return json_dict


def write_json(fname, meta_dict):
    """
    Write a dictionary to a JSON file
    :param fname: string
        JSON filename
    :param meta_dict: dictionary
        Dictionary
    :return:
    """
    with open(fname, 'w') as fd:
        json.dump(meta_dict, fd, indent=4, separators=(',', ':'))

# This is the standard boilerplate that calls the main() function.
if __name__ == '__main__':
    main()
@jmtyszka
Copy link
Owner

jmtyszka commented Mar 5, 2018

Thanks for the detailed info on this Charlotte. I'll have time to work on the active issues this week, so hopefully will have an update fixing this issue by next week.

@celstark
Copy link
Contributor

celstark commented Mar 7, 2018

The "IntendedFor" issue is related to / the same as #20

jmtyszka added a commit that referenced this issue Mar 9, 2018
…grated to pydicom v1.0.1 (note namespace change to pydicom).
@jmtyszka
Copy link
Owner

jmtyszka commented Mar 9, 2018

I've just pushed v1.1.0 which fixes the IntendedFor issues (see Issue #20 closing notes). No need to include the ses-* directory name in the IntendedFor template field in the protocol translator. If you apply one fieldmap to many EPI runs, make sure to list them explicitly in the IntendedFor field, enclosed by square brackets (eg Protocol_Translator.json.txt )

The TotalReadoutTime and MultibandAccelerationFactor are handled as well as possible by dcm2niix (see for example rordenlab/dcm2niix#130 and rordenlab/dcm2niix#141).

If the information required to generate these fields isn't present in the DICOM header, they'll have to be calculated and added manually as you did above in your script. Both these fields appear to be populated correctly for conversions of the CMRR MB sequence from our VE11C Prisma (eg sub-Sphere32_ses-1_task-mb6_run-01_bold.json.txt ).

@jmtyszka jmtyszka closed this as completed Mar 9, 2018
@ccharpen
Copy link
Author

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants