@@ -233,6 +233,95 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
233
233
getattr (heuristic , 'DEFAULT_FIELDS' , {}))
234
234
235
235
236
+ def update_complex_name (fileinfo , this_prefix_basename , suffix ):
237
+ """
238
+ Insert `_part-<mag|phase>` entity into filename if data are from a sequence
239
+ with magnitude/phase reconstruction.
240
+ """
241
+ unsupported_types = ['_bold' , '_phase' ]
242
+ if suffix in unsupported_types :
243
+ return this_prefix_basename
244
+
245
+ # Check to see if it is magnitude or phase reconstruction:
246
+ if 'M' in fileinfo .get ('ImageType' ):
247
+ mag_or_phase = 'mag'
248
+ elif 'P' in fileinfo .get ('ImageType' ):
249
+ mag_or_phase = 'phase'
250
+ else :
251
+ mag_or_phase = suffix
252
+
253
+ # Insert reconstruction label
254
+ if not ('_part-%s' % mag_or_phase ) in this_prefix_basename :
255
+
256
+ # If "_part-" is specified, prepend the 'mag_or_phase' value.
257
+ if '_part-' in this_prefix_basename :
258
+ raise BIDSError (
259
+ "Part label for images will be automatically set, remove "
260
+ "from heuristic"
261
+ )
262
+
263
+ # If not, insert "_part-" + 'mag_or_phase' into the prefix_basename
264
+ # **before** "_run", "_echo" or "_sbref", whichever appears first:
265
+ for label in ['_run' , '_echo' , '_sbref' ]:
266
+ if (label in this_prefix_basename ):
267
+ this_prefix_basename = this_prefix_basename .replace (
268
+ label , "_part-%s%s" % (mag_or_phase , label )
269
+ )
270
+ break
271
+ return this_prefix_basename
272
+
273
+
274
+ def update_multiecho_name (fileinfo , this_prefix_basename , echo_times , suffix ):
275
+ """
276
+ Insert `_echo-<num>` entity into filename if data are from a multi-echo
277
+ sequence.
278
+ """
279
+ unsupported_types = ['_magnitude1' , '_magnitude2' , '_phasediff' , '_phase1' , '_phase2' ]
280
+ if suffix in unsupported_types :
281
+ return this_prefix_basename
282
+
283
+ # Get the EchoNumber from json file info. If not present, use EchoTime
284
+ if 'EchoNumber' in fileinfo .keys ():
285
+ echo_number = fileinfo ['EchoNumber' ]
286
+ else :
287
+ echo_number = echo_times .index (fileinfo ['EchoTime' ]) + 1
288
+
289
+ # Now, decide where to insert it.
290
+ # Insert it **before** the following string(s), whichever appears first.
291
+ for imgtype in supported_multiecho :
292
+ if (imgtype in this_prefix_basename ):
293
+ this_prefix_basename = this_prefix_basename .replace (
294
+ imgtype , "_echo-%d%s" % (echo_number , imgtype )
295
+ )
296
+ break
297
+ return this_prefix_basename
298
+
299
+
300
+ def update_uncombined_name (fileinfo , this_prefix_basename , coil_names , suffix ):
301
+ """
302
+ Insert `_channel-<num>` entity into filename if data are from a sequence
303
+ with "save uncombined".
304
+ """
305
+ # Determine the channel number
306
+ channel_number = coil_names .index (fileinfo ['CoilString' ]) + 1
307
+
308
+ # Insert it **before** the following string(s), whichever appears first.
309
+ for label in ['_run' , '_echo' , suffix ]:
310
+ if label == suffix :
311
+ prefix_suffix = this_prefix_basename .split ('_' )[- 1 ]
312
+ this_prefix_basename = this_prefix_basename .replace (
313
+ prefix_suffix , "_channel-%s_%s" % (channel_number , prefix_suffix )
314
+ )
315
+ break
316
+
317
+ if (label in this_prefix_basename ):
318
+ this_prefix_basename = this_prefix_basename .replace (
319
+ label , "_channel-%s%s" % (coil_number , label )
320
+ )
321
+ break
322
+ return this_prefix_basename
323
+
324
+
236
325
def convert (items , converter , scaninfo_suffix , custom_callable , with_prov ,
237
326
bids_options , outdir , min_meta , overwrite , symlink = True , prov_file = None ,
238
327
dcmconfig = None ):
@@ -534,14 +623,28 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
534
623
# series. To do that, the most straightforward way is to read the
535
624
# echo times for all bids_files and see if they are all the same or not.
536
625
537
- # Check for varying echo times
538
- echo_times = sorted (list (set (
539
- b .get ('EchoTime' , nan )
540
- for b in bids_metas
541
- if b
542
- )))
543
-
544
- is_multiecho = len (echo_times ) > 1
626
+ # Collect some metadata across all images
627
+ echo_times , channel_names , image_types = [], [], []
628
+ for metadata in bids_metas :
629
+ if not metadata :
630
+ continue
631
+ echo_times .append (metadata .get ('EchoTime' , None ))
632
+ channel_names .append (metadata .get ('CoilString' , None ))
633
+ image_types .append (metadata .get ('ImageType' , None ))
634
+ echo_times = [v for v in echo_times if v ]
635
+ echo_times = sorted (list (set (echo_times )))
636
+ channel_names = [v for v in channel_names if v ]
637
+ channel_names = sorted (list (set (channel_names )))
638
+ image_types = [v for v in image_types if v ]
639
+ image_types = sorted (list (set (image_types )))
640
+
641
+ is_multiecho = len (echo_times ) > 1 # Check for varying echo times
642
+ is_uncombined = len (coil_names ) > 1 # Check for uncombined data
643
+
644
+ # Determine if data are complex (magnitude + phase)
645
+ magnitude_found = ['M' in it for it in image_types ]
646
+ phase_found = ['P' in it for it in image_types ]
647
+ is_complex = magnitude_found and phase_found
545
648
546
649
### Loop through the bids_files, set the output name and save files
547
650
for fl , suffix , bids_file , bids_meta in zip (res_files , suffixes , bids_files , bids_metas ):
@@ -552,65 +655,26 @@ def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outnam
552
655
# and we don't want to modify it for all the bids_files):
553
656
this_prefix_basename = prefix_basename
554
657
555
- # _sbref sequences reconstructing magnitude and phase generate
556
- # two NIfTI files IN THE SAME SERIES, so we cannot just add
557
- # the suffix, if we want to be bids compliant:
558
- if bids_meta and this_prefix_basename .endswith ('_sbref' ) \
559
- and len (suffixes ) > len (echo_times ):
560
- if len (suffixes ) != len (echo_times )* 2 :
561
- lgr .warning (
562
- "Got %d suffixes for %d echo times, which isn't "
563
- "multiple of two as if it was magnitude + phase pairs" ,
564
- len (suffixes ), len (echo_times )
565
- )
566
- # Check to see if it is magnitude or phase reconstruction:
567
- if 'M' in bids_meta .get ('ImageType' ):
568
- mag_or_phase = 'magnitude'
569
- elif 'P' in bids_meta .get ('ImageType' ):
570
- mag_or_phase = 'phase'
571
- else :
572
- mag_or_phase = suffix
573
-
574
- # Insert reconstruction label
575
- if not ("_rec-%s" % mag_or_phase ) in this_prefix_basename :
576
-
577
- # If "_rec-" is specified, prepend the 'mag_or_phase' value.
578
- if ('_rec-' in this_prefix_basename ):
579
- raise BIDSError (
580
- "Reconstruction label for multi-echo single-band"
581
- " reference images will be automatically set, remove"
582
- " from heuristic"
583
- )
584
-
585
- # If not, insert "_rec-" + 'mag_or_phase' into the prefix_basename
586
- # **before** "_run", "_echo" or "_sbref", whichever appears first:
587
- for label in ['_run' , '_echo' , '_sbref' ]:
588
- if (label in this_prefix_basename ):
589
- this_prefix_basename = this_prefix_basename .replace (
590
- label , "_rec-%s%s" % (mag_or_phase , label )
591
- )
592
- break
593
-
594
- # Now check if this run is multi-echo
658
+ # Update name if complex data
659
+ if bids_file and is_complex :
660
+ this_prefix_basename = update_complex_name (
661
+ bids_meta , this_prefix_basename , suffix
662
+ )
663
+
664
+ # Update name if multi-echo
595
665
# (Note: it can be _sbref and multiecho, so don't use "elif"):
596
666
# For multi-echo sequences, we have to specify the echo number in
597
667
# the file name:
598
- if bids_meta and is_multiecho :
599
- # Get the EchoNumber from json file info. If not present, use EchoTime
600
- if 'EchoNumber' in bids_meta :
601
- echo_number = bids_meta ['EchoNumber' ]
602
- else :
603
- echo_number = echo_times .index (bids_meta ['EchoTime' ]) + 1
604
-
605
- supported_multiecho = ['_bold' , '_phase' , '_epi' , '_sbref' , '_T1w' , '_PDT2' ]
606
- # Now, decide where to insert it.
607
- # Insert it **before** the following string(s), whichever appears first.
608
- for imgtype in supported_multiecho :
609
- if (imgtype in this_prefix_basename ):
610
- this_prefix_basename = this_prefix_basename .replace (
611
- imgtype , "_echo-%d%s" % (echo_number , imgtype )
612
- )
613
- break
668
+ if bids_file and is_multiecho :
669
+ this_prefix_basename = update_multiecho_name (
670
+ bids_meta , this_prefix_basename , echo_times , suffix
671
+ )
672
+
673
+ # Update name if uncombined (channel-level) data
674
+ if bids_file and is_uncombined :
675
+ this_prefix_basename = update_uncombined_name (
676
+ bids_meta , this_prefix_basename , channel_names
677
+ )
614
678
615
679
# Fallback option:
616
680
# If we have failed to modify this_prefix_basename, because it didn't fall
0 commit comments