Repository: nipy/heudiconv

Issue:
Replace rec entity with part entity for complex-valued data
<!-- DO NOT DELETE THIS! 
This template is used to facilitate issue resolution.
All text in <!-> tags will not be displayed.
-->

### Summary
<!-- If you are having conversion troubles, please share as much
relevant information as possible. This includes, but is not limited to:
- log of conversion
- heuristic
-->
Now that bids-standard/bids-specification#424 has been merged, BIDS will support the `part` entity for dissociating magnitude and phase data in its next release. Currently, heudiconv uses `rec-<magnitude|phase>` instead. To fix this, [`heudiconv.convert.update_complex_name()`](https://github.com/nipy/heudiconv/blob/d855f64d5013f8a0e41789766a094d3c3a91552f/heudiconv/convert.py#L236) needs to be updated to use `part` instead of `rec` (also `magnitude` needs to changed to `mag`).


### Platform details:

Choose one:
- [ ] Local environment
<!-- If selected, please provide OS and python version -->
- [ ] Container
<!-- If selected, please provide container name and tag"-->

- Heudiconv version: 
<!-- To check: run heudiconv with just the --version flag -->


Discussion:

Patch:
diff --git a/heudiconv/convert.py b/heudiconv/convert.py
index 8e2c3c6..b88c232 100644
--- a/heudiconv/convert.py
+++ b/heudiconv/convert.py
@@ -235,7 +235,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
 
 def update_complex_name(metadata, filename, suffix):
     """
-    Insert `_rec-<magnitude|phase>` entity into filename if data are from a
+    Insert `_part-<mag|phase>` entity into filename if data are from a
     sequence with magnitude/phase part.
 
     Parameters
@@ -254,7 +254,10 @@ def update_complex_name(metadata, filename, suffix):
         Updated filename with rec entity added in appropriate position.
     """
     # Some scans separate magnitude/phase differently
-    unsupported_types = ['_bold', '_phase',
+    # A small note: _phase is deprecated, but this may add part-mag to
+    # magnitude data while leaving phase data with a separate suffix,
+    # depending on how one sets up their heuristic.
+    unsupported_types = ['_phase',
                          '_magnitude', '_magnitude1', '_magnitude2',
                          '_phasediff', '_phase1', '_phase2']
     if any(ut in filename for ut in unsupported_types):
@@ -262,7 +265,7 @@ def update_complex_name(metadata, filename, suffix):
 
     # Check to see if it is magnitude or phase part:
     if 'M' in metadata.get('ImageType'):
-        mag_or_phase = 'magnitude'
+        mag_or_phase = 'mag'
     elif 'P' in metadata.get('ImageType'):
         mag_or_phase = 'phase'
     else:
@@ -272,19 +275,19 @@ def update_complex_name(metadata, filename, suffix):
     filetype = '_' + filename.split('_')[-1]
 
     # Insert rec label
-    if not ('_rec-%s' % mag_or_phase) in filename:
-        # If "_rec-" is specified, prepend the 'mag_or_phase' value.
-        if '_rec-' in filename:
+    if not ('_part-%s' % mag_or_phase) in filename:
+        # If "_part-" is specified, prepend the 'mag_or_phase' value.
+        if '_part-' in filename:
             raise BIDSError(
-                "Reconstruction label for images will be automatically set, "
+                "Part label for images will be automatically set, "
                 "remove from heuristic"
             )
 
         # Insert it **before** the following string(s), whichever appears first.
-        for label in ['_dir', '_run', '_mod', '_echo', '_recording', '_proc', '_space', filetype]:
+        for label in ['_recording', '_proc', '_space', filetype]:
             if (label == filetype) or (label in filename):
                 filename = filename.replace(
-                    label, "_rec-%s%s" % (mag_or_phase, label)
+                    label, "_part-%s%s" % (mag_or_phase, label)
                 )
                 break
 


Test patch:
diff --git a/heudiconv/tests/test_convert.py b/heudiconv/tests/test_convert.py
index 7593cb0..75c2194 100644
--- a/heudiconv/tests/test_convert.py
+++ b/heudiconv/tests/test_convert.py
@@ -10,13 +10,13 @@ from heudiconv.bids import BIDSError
 
 def test_update_complex_name():
     """Unit testing for heudiconv.convert.update_complex_name(), which updates
-    filenames with the rec field if appropriate.
+    filenames with the part field if appropriate.
     """
     # Standard name update
     fn = 'sub-X_ses-Y_task-Z_run-01_sbref'
     metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'P', 'MB', 'TE3', 'ND', 'MOSAIC']}
     suffix = 3
-    out_fn_true = 'sub-X_ses-Y_task-Z_rec-phase_run-01_sbref'
+    out_fn_true = 'sub-X_ses-Y_task-Z_run-01_part-phase_sbref'
     out_fn_test = update_complex_name(metadata, fn, suffix)
     assert out_fn_test == out_fn_true
     # Catch an unsupported type and *do not* update
@@ -26,12 +26,12 @@ def test_update_complex_name():
     # Data type is missing from metadata so use suffix
     fn = 'sub-X_ses-Y_task-Z_run-01_sbref'
     metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'MB', 'TE3', 'ND', 'MOSAIC']}
-    out_fn_true = 'sub-X_ses-Y_task-Z_rec-3_run-01_sbref'
+    out_fn_true = 'sub-X_ses-Y_task-Z_run-01_part-3_sbref'
     out_fn_test = update_complex_name(metadata, fn, suffix)
     assert out_fn_test == out_fn_true
     # Catch existing field with value that *does not match* metadata
     # and raise Exception
-    fn = 'sub-X_ses-Y_task-Z_rec-magnitude_run-01_sbref'
+    fn = 'sub-X_ses-Y_task-Z_run-01_part-mag_sbref'
     metadata = {'ImageType': ['ORIGINAL', 'PRIMARY', 'P', 'MB', 'TE3', 'ND', 'MOSAIC']}
     suffix = 3
     with pytest.raises(BIDSError):