Skip to content

Commit 74d9140

Browse files
authored
Merge pull request #387 from tsalo/mbme-reproin
ENH: Support SBRef and phase data in ReproIn heuristic
2 parents 09f7501 + dce8e23 commit 74d9140

File tree

4 files changed

+72
-39
lines changed

4 files changed

+72
-39
lines changed

heudiconv/convert.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,8 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
518518
bids_files = (sorted(res.outputs.bids)
519519
if len(res.outputs.bids) == len(res_files)
520520
else [None] * len(res_files))
521+
# preload since will be used in multiple spots
522+
bids_metas = [load_json(b) for b in bids_files if b]
521523

522524
### Do we have a multi-echo series? ###
523525
# Some Siemens sequences (e.g. CMRR's MB-EPI) set the label 'TE1',
@@ -531,19 +533,17 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
531533

532534
# Check for varying echo times
533535
echo_times = sorted(list(set(
534-
load_json(b).get('EchoTime', nan)
535-
for b in bids_files
536+
b.get('EchoTime', nan)
537+
for b in bids_metas
536538
if b
537539
)))
538540

539541
is_multiecho = len(echo_times) > 1
540542

541543
### Loop through the bids_files, set the output name and save files
542-
for fl, suffix, bids_file in zip(res_files, suffixes, bids_files):
544+
for fl, suffix, bids_file, bids_meta in zip(res_files, suffixes, bids_files, bids_metas):
543545

544546
# TODO: monitor conversion duration
545-
if bids_file:
546-
fileinfo = load_json(bids_file)
547547

548548
# set the prefix basename for this specific file (we'll modify it,
549549
# and we don't want to modify it for all the bids_files):
@@ -552,11 +552,18 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
552552
# _sbref sequences reconstructing magnitude and phase generate
553553
# two NIfTI files IN THE SAME SERIES, so we cannot just add
554554
# the suffix, if we want to be bids compliant:
555-
if bids_file and this_prefix_basename.endswith('_sbref'):
555+
if bids_meta and this_prefix_basename.endswith('_sbref') \
556+
and len(suffixes) > len(echo_times):
557+
if len(suffixes) != len(echo_times)*2:
558+
lgr.warning(
559+
"Got %d suffixes for %d echo times, which isn't "
560+
"multiple of two as if it was magnitude + phase pairs",
561+
len(suffixes), len(echo_times)
562+
)
556563
# Check to see if it is magnitude or phase reconstruction:
557-
if 'M' in fileinfo.get('ImageType'):
564+
if 'M' in bids_meta.get('ImageType'):
558565
mag_or_phase = 'magnitude'
559-
elif 'P' in fileinfo.get('ImageType'):
566+
elif 'P' in bids_meta.get('ImageType'):
560567
mag_or_phase = 'phase'
561568
else:
562569
mag_or_phase = suffix
@@ -585,12 +592,12 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
585592
# (Note: it can be _sbref and multiecho, so don't use "elif"):
586593
# For multi-echo sequences, we have to specify the echo number in
587594
# the file name:
588-
if bids_file and is_multiecho:
595+
if bids_meta and is_multiecho:
589596
# Get the EchoNumber from json file info. If not present, use EchoTime
590-
if 'EchoNumber' in fileinfo.keys():
591-
echo_number = fileinfo['EchoNumber']
597+
if 'EchoNumber' in bids_meta:
598+
echo_number = bids_meta['EchoNumber']
592599
else:
593-
echo_number = echo_times.index(fileinfo['EchoTime']) + 1
600+
echo_number = echo_times.index(bids_meta['EchoTime']) + 1
594601

595602
supported_multiecho = ['_bold', '_phase', '_epi', '_sbref', '_T1w', '_PDT2']
596603
# Now, decide where to insert it.

heudiconv/external/dlad.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
lgr = logging.getLogger(__name__)
1212

13-
MIN_VERSION = '0.12.2'
13+
MIN_VERSION = '0.12.4'
1414

1515

1616
def prepare_datalad(studydir, outdir, sid, session, seqinfo, dicoms, bids):
@@ -177,4 +177,4 @@ def mark_sensitive(ds, path_glob):
177177
init=dict([('distribution-restrictions', 'sensitive')]),
178178
recursive=True)
179179
if inspect.isgenerator(res):
180-
res = list(res)
180+
res = list(res)

heudiconv/heuristics/reproin.py

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -514,10 +514,10 @@ def infotodict(seqinfo):
514514
# 3 - Image IOD specific specialization (optional)
515515
dcm_image_iod_spec = s.image_type[2]
516516
image_type_seqtype = {
517-
'P': 'fmap', # phase
517+
# Note: P and M are too generic to make a decision here, could be
518+
# for different seqtypes (bold, fmap, etc)
518519
'FMRI': 'func',
519520
'MPR': 'anat',
520-
# 'M': 'func', "magnitude" -- can be for scout, anat, bold, fmap
521521
'DIFFUSION': 'dwi',
522522
'MIP_SAG': 'anat', # angiography
523523
'MIP_COR': 'anat', # angiography
@@ -570,29 +570,55 @@ def infotodict(seqinfo):
570570
# prefix = ''
571571
prefix = ''
572572

573+
#
574+
# Figure out the seqtype_label (BIDS _suffix)
575+
#
576+
# If none was provided -- let's deduce it from the information we find:
573577
# analyze s.protocol_name (series_id is based on it) for full name mapping etc
574-
if seqtype == 'func' and not seqtype_label:
575-
if '_pace_' in series_spec:
576-
seqtype_label = 'pace' # or should it be part of seq-
577-
else:
578-
# assume bold by default
579-
seqtype_label = 'bold'
580-
581-
if seqtype == 'fmap' and not seqtype_label:
582-
if not dcm_image_iod_spec:
583-
raise ValueError("Do not know image data type yet to make decision")
584-
seqtype_label = {
585-
# might want explicit {file_index} ?
586-
# _epi for pepolar fieldmaps, see
587-
# https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#case-4-multiple-phase-encoded-directions-pepolar
588-
'M': 'epi' if 'dir' in series_info else 'magnitude',
589-
'P': 'phasediff',
590-
'DIFFUSION': 'epi', # according to KODI those DWI are the EPIs we need
591-
}[dcm_image_iod_spec]
592-
593-
# label for dwi as well
594-
if seqtype == 'dwi' and not seqtype_label:
595-
seqtype_label = 'dwi'
578+
if not seqtype_label:
579+
if seqtype == 'func':
580+
if '_pace_' in series_spec:
581+
seqtype_label = 'pace' # or should it be part of seq-
582+
elif 'P' in s.image_type:
583+
seqtype_label = 'phase'
584+
elif 'M' in s.image_type:
585+
seqtype_label = 'bold'
586+
else:
587+
# assume bold by default
588+
seqtype_label = 'bold'
589+
elif seqtype == 'fmap':
590+
# TODO: support phase1 phase2 like in "Case 2: Two phase images ..."
591+
if not dcm_image_iod_spec:
592+
raise ValueError("Do not know image data type yet to make decision")
593+
seqtype_label = {
594+
# might want explicit {file_index} ?
595+
# _epi for pepolar fieldmaps, see
596+
# https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/01-magnetic-resonance-imaging-data.html#case-4-multiple-phase-encoded-directions-pepolar
597+
'M': 'epi' if 'dir' in series_info else 'magnitude',
598+
'P': 'phasediff',
599+
'DIFFUSION': 'epi', # according to KODI those DWI are the EPIs we need
600+
}[dcm_image_iod_spec]
601+
elif seqtype == 'dwi':
602+
# label for dwi as well
603+
seqtype_label = 'dwi'
604+
605+
#
606+
# Even if seqtype_label was provided, for some data we might need to override,
607+
# since they are complementary files produced along-side with original
608+
# ones.
609+
#
610+
if s.series_description.endswith('_SBRef'):
611+
seqtype_label = 'sbref'
612+
613+
if not seqtype_label:
614+
# Might be provided by the bids ending within series_spec, we would
615+
# just want to check if that the last element is not _key-value pair
616+
bids_ending = series_info.get('bids', None)
617+
if not bids_ending \
618+
or "-" in bids_ending.split('_')[-1]:
619+
lgr.warning(
620+
"We ended up with an empty label/suffix for %r",
621+
series_spec)
596622

597623
run = series_info.get('run')
598624
if run is not None:

heudiconv/info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
EXTRA_REQUIRES = {
4343
'tests': TESTS_REQUIRES,
4444
'extras': [], # Requires patched version ATM ['dcmstack'],
45-
'datalad': ['datalad >=0.12.2']
45+
'datalad': ['datalad >=0.12.3']
4646
}
4747

4848
# Flatten the lists

0 commit comments

Comments
 (0)