Skip to content

Commit 3250283

Browse files
committed
rf+enh: ME support, custom BIDS exception
1 parent f053c0b commit 3250283

File tree

2 files changed

+61
-44
lines changed

2 files changed

+61
-44
lines changed

heudiconv/bids.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424

2525
lgr = logging.getLogger(__name__)
2626

27+
28+
class BIDSException(Exception):
29+
pass
30+
31+
2732
def populate_bids_templates(path, defaults={}):
2833
"""Premake BIDS text files with templates"""
2934

heudiconv/convert.py

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
save_scans_key,
2525
tuneup_bids_json_files,
2626
add_participant_record,
27+
BIDSException
2728
)
2829
from .dicoms import (
2930
group_dicoms_into_seqinfos,
@@ -486,73 +487,83 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
486487
# series. To do that, the most straightforward way is to read the
487488
# echo times for all bids_files and see if they are all the same or not.
488489

489-
# Get the echo times:
490-
echoTimes = [load_json(bids_file).get('EchoTime') for bids_file in bids_files]
490+
# Get the echo times while not breaking non-BIDS compliance
491+
echo_times = []
492+
for bids_file in bids_files:
493+
if bids_file:
494+
echo_times.append(load_json(bids_file).get('EchoTime'))
491495

492496
# To see if the echo times are the same, convert it to a set and see if
493497
# only one remains:
494-
if ( len(set(echoTimes)) == 1 ): multiecho = False
495-
else : multiecho = True
498+
multiecho = False
499+
if echo_times:
500+
multiecho = len(set(echo_times)) == 1
496501

497-
### Loop through the bids_files, set the output name and save files ###
502+
### Loop through the bids_files, set the output name and save files
498503

499504
for fl, suffix, bids_file in zip(res_files, suffixes, bids_files):
500505
# load the json file info:
501-
fileinfo = load_json(bids_file)
506+
# TODO: time performance
507+
if bids_file:
508+
fileinfo = load_json(bids_file)
502509

503-
# set the prefix basename for this specific file (we'll modify it, and
504-
# we don't want to modify it for all the bids_files):
510+
# set the prefix basename for this specific file (we'll modify it,
511+
# and we don't want to modify it for all the bids_files):
505512
this_prefix_basename = prefix_basename
506513

507514
# _sbref sequences reconstructing magnitude and phase generate
508515
# two NIfTI files IN THE SAME SERIES, so we cannot just add
509516
# the suffix, if we want to be bids compliant:
510-
if ( bids and (this_prefix_basename[-6:] == '_sbref') ):
517+
if (bids_file and (this_prefix_basename.endswith('_sbref'))):
511518
# Check to see if it is magnitude or phase reconstruction:
512-
if ('M' in fileinfo.get('ImageType')): mag_or_phase = 'magnitude'
513-
elif ('P' in fileinfo.get('ImageType')): mag_or_phase = 'phase'
514-
else : mag_or_phase = suffix
519+
if 'M' in fileinfo.get('ImageType'):
520+
mag_or_phase = 'magnitude'
521+
elif 'P' in fileinfo.get('ImageType'):
522+
mag_or_phase = 'phase'
523+
else:
524+
mag_or_phase = suffix
515525

516-
# If "_rec-'mag_or_phase'" is not already there, check where to insert it:
526+
# Insert reconstruction label
517527
if not (("_rec-%s" % mag_or_phase) in this_prefix_basename):
518528

519-
# If "_rec-" is specified, append the 'mag_or_phase' value.
529+
# If "_rec-" is specified, prepend the 'mag_or_phase' value.
520530
if ('_rec-' in this_prefix_basename):
521-
spt = this_prefix_basename.split('_rec-',1)
522-
# grab the reconstruction type (grab whatever we have before the next "_"):
523-
spt_spt = spt[1].split('_',1)
524-
# update 'this_prefix_basename':
525-
this_prefix_basename = "%s_rec-%s-%s_%s" % (spt[0], spt_spt[0], mag_or_phase, spt_spt[1])
531+
raise BIDSException(
532+
"Reconstruction label for multi-echo single-band"
533+
" reference images will be automatically set, remove"
534+
" from heuristic"
535+
)
526536

527537
# If not, insert "_rec-" + 'mag_or_phase' into the prefix_basename
528538
# **before** "_run", "_echo" or "_sbref", whichever appears first:
529-
else:
530-
for my_str in ['_run', '_echo', '_sbref']:
531-
if (my_str in this_prefix_basename):
532-
spt = this_prefix_basename.split(my_str, 1)
533-
this_prefix_basename = "%s_rec-%s%s%s" % (spt[0], mag_or_phase, my_str, spt[1])
534-
break
535-
536-
# Now check if this run is multi-echo (Note: it can be _sbref and multiecho, so
537-
# don't use "elif"):
538-
# For multi-echo sequences, we have to specify the echo number in the file name:
539-
if ( bids and multiecho ):
539+
for label in ['_run', '_echo', '_sbref']:
540+
if (label in this_prefix_basename):
541+
this_prefix_basename = this_prefix_basename.replace(
542+
label, "_rec-%s%s" % (mag_or_phase, label)
543+
)
544+
break
545+
546+
# Now check if this run is multi-echo
547+
# (Note: it can be _sbref and multiecho, so don't use "elif"):
548+
# For multi-echo sequences, we have to specify the echo number in
549+
# the file name:
550+
if bids and multiecho:
540551
# Get the EchoNumber from json file info. If not present, it's echo-1
541-
echoNumber=( fileinfo.get('EchoNumber') or 1 )
552+
echo_number = fileinfo.get('EchoNumber', 1)
553+
542554

555+
supported_multiecho = ['_bold', '_sbref', '_T1w'] # epi?
543556
# Now, decide where to insert it.
544557
# Insert it **before** the following string(s), whichever appears first.
545-
# (Note: If you decide to support multi-echo for other sequences (e.g.
546-
# ME-MPRAGE), add the string before which you want to add the echo number
547-
# to the list below):
548-
for my_str in ['_bold', '_sbref', '_T1w']:
549-
if (my_str in this_prefix_basename):
550-
spt = this_prefix_basename.split(my_str, 1)
551-
this_prefix_basename = "%s_echo-%s%s%s" % (spt[0], echoNumber, my_str, spt[1])
558+
for imgtype in ['_bold', '_sbref', '_T1w']:
559+
if (imgtype in this_prefix_basename):
560+
this_prefix_basename = this_prefix_basename.replace(
561+
imgtype, "_echo-%d%s" % (echo_number, imgtype)
562+
)
552563
break
553564

554565
# For Scout runs with multiple NIfTI images per run:
555-
if ( bids and ('scout' in this_prefix_basename.lower()) ):
566+
if (bids and ('scout' in this_prefix_basename.lower())):
556567
# in some cases (more than one slice slab), there are several
557568
# NIfTI images in the scout run, so distinguish them with "_acq-"
558569
spt = this_prefix_basename.split('_acq-Scout', 1)
@@ -562,15 +573,16 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
562573
# If we have failed to modify this_prefix_basename, because it didn't fall
563574
# into any of the options above, just add the suffix at the end:
564575
if ( this_prefix_basename == prefix_basename ):
565-
this_prefix_basename = "%s%s" % (this_prefix_basename, suffix)
576+
this_prefix_basename += suffix
566577

567-
# Finally, form the outname by stitch the directory and outtype:
568-
outname = "%s/%s.%s" % (prefix_dirname, this_prefix_basename, outtype)
578+
# Finally, form the outname by stitching the directory and outtype:
579+
outname = op.join(prefix_dirname, this_prefix_basename)
580+
outfile = outname + '.' + outtype
569581

570582
# Write the files needed:
571-
safe_copyfile(fl, outname, overwrite)
583+
safe_copyfile(fl, outfile, overwrite)
572584
if bids_file:
573-
outname_bids_file = "%s.json" % (outname.strip(outtype))
585+
outname_bids_file = "%s.json" % (outname)
574586
safe_copyfile(bids_file, outname_bids_file, overwrite)
575587
bids_outfiles.append(outname_bids_file)
576588
# res_files is not a list

0 commit comments

Comments
 (0)