Repository: mne-tools/mne-bids

Issue:
API error in 'write_raw_bids': channel type mappings description is not correct. KeyError: 'grad'
### Description of the problem


We have a Neuromag-122 system which is equipped with 61 dual-channel planar first-order gradiometers. 
I am trying to convert our local meg files to MNE-BIDS format using write_raw_bids API. The API prompts the following error. 




 

### Steps to reproduce

```Python
***Error description*:**

Traceback (most recent call last):
  File "/media/dip_linux/18F80D53F80D3094/Auditory_P3/x_Dip_p300/auditory_code/regression_model/MNE_BIDs.py", line 99, in <module>
    write_raw_bids(
  File "<decorator-gen-627>", line 12, in write_raw_bids
  File "/home/dip_linux/anaconda3/envs/mne/lib/python3.10/site-packages/mne_bids/write.py", line 1865, in write_raw_bids
    _channels_tsv(raw, channels_path.fpath, overwrite)
  File "/home/dip_linux/anaconda3/envs/mne/lib/python3.10/site-packages/mne_bids/write.py", line 126, in _channels_tsv
    ch_type.append(map_chs[_channel_type])
KeyError: 'grad'


# It seems channel type mappings description is not correct. 
Currently its written as: 
# line 90: 
map_desc.update(meggradaxial='Axial Gradiometer',
                        megrefgradaxial='Axial Gradiometer Reference',
                        meggradplanar='Planar Gradiometer',
                        megmag='Magnetometer',
                        megrefmag='Magnetometer Reference',
                        stim='Trigger',
                        eeg='ElectroEncephaloGram',
                        ecog='Electrocorticography',
                        seeg='StereoEEG',
                        ecg='ElectroCardioGram',
                        eog='ElectroOculoGram',
                        emg='ElectroMyoGram',
                        misc='Miscellaneous',
                        bio='Biological',
                        ias='Internal Active Shielding',
                        dbs='Deep Brain Stimulation',
                        fnirs_cw_amplitude='Near Infrared Spectroscopy '
                                           '(continuous wave)',
                        resp='Respiration',
                        gsr='Galvanic skin response (electrodermal activity, EDA)',
                        temperature='Temperature',)

    # get the manufacturer from the file in the Raw object
    _, ext = _parse_ext(raw.filenames[0])
    manufacturer = MANUFACTURERS.get(ext, '')
    ignored_channels = IGNORED_CHANNELS.get(manufacturer, list())

    status, ch_type, description = list(), list(), list()
    for idx, ch in enumerate(raw.info['ch_names']):
        status.append('bad' if ch in raw.info['bads'] else 'good')
        _channel_type = channel_type(raw.info, idx)
        if _channel_type in get_specific:
            _channel_type = coil_type(raw.info, idx, _channel_type)
        ch_type.append(map_chs[_channel_type])    
        description.append(map_desc[_channel_type])   # error prompt line 126
```


### Expected results

current system outputs:

map_desc output is:

defaultdict(<function _channels_tsv.<locals>.<lambda> at 0x7f7705bcadd0>, {'meggradaxial': 'Axial Gradiometer', 'megrefgradaxial': 'Axial Gradiometer Reference', 'meggradplanar': 'Planar Gradiometer', 'megmag': 'Magnetometer', 'megrefmag': 'Magnetometer Reference', 'stim': 'Trigger', 'eeg': 'ElectroEncephaloGram', 'ecog': 'Electrocorticography', 'seeg': 'StereoEEG', 'ecg': 'ElectroCardioGram', 'eog': 'ElectroOculoGram', 'emg': 'ElectroMyoGram', 'misc': 'Miscellaneous', 'bio': 'Biological', 'ias': 'Internal Active Shielding', 'dbs': 'Deep Brain Stimulation', 'fnirs_cw_amplitude': 'Near Infrared Spectroscopy (continuous wave)', 'resp': 'Respiration', 'gsr': 'Galvanic skin response (electrodermal activity, EDA)', 'temperature': 'Temperature'})

 _channel_type output is: 
'grad'


### Actual results

######### error line 126
ch_type.append(map_chs[_channel_type]) 
map_chs[_channel_type] expects the key word 'meggradplanar' instead of 'grad'


### Additional information
Platform:         Linux-5.15.0-52-generic-x86_64-with-glibc2.31
Python:           3.10.6 | packaged by conda-forge | (main, Aug 22 2022, 20:35:26) [GCC 10.4.0]
Executable:       /home/dip_linux/anaconda3/envs/mne/bin/python3.10
CPU:              x86_64: 8 cores
Memory:           15.3 GB

mne:              1.2.3
numpy:            1.22.4 {OpenBLAS 0.3.21 with 8 threads}
scipy:            1.9.1
matplotlib:       3.6.0 {backend=QtAgg}

sklearn:          1.1.2
numba:            0.55.2
nibabel:          4.0.2
nilearn:          0.9.2
dipy:             1.5.0
openmeeg:         Not found
cupy:             Not found
pandas:           1.5.0
pyvista:          0.36.1 {OpenGL 3.3 (Core Profile) Mesa 21.2.6 via Mesa Intel(R) UHD Graphics (CML GT2)}
pyvistaqt:        0.9.0
ipyvtklink:       0.2.2
vtk:              9.1.0
qtpy:             2.2.0 {PyQt5=5.12.10}
ipympl:           Not found
pyqtgraph:        0.12.4
pooch:            v1.6.0

mne_bids:         0.12.dev0
mne_nirs:         Not found
mne_features:     Not found
mne_qt_browser:   0.3.2
mne_connectivity: 0.4.0
mne_icalabel:     Not found



Discussion:
Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴🏽‍♂️


Resolving patch:
diff --git a/mne_bids/pick.py b/mne_bids/pick.py
--- a/mne_bids/pick.py
+++ b/mne_bids/pick.py
@@ -34,6 +34,7 @@ def get_coil_types():
                         FIFF.FIFFV_COIL_VV_MAG_T1,
                         FIFF.FIFFV_COIL_VV_MAG_T2,
                         FIFF.FIFFV_COIL_VV_MAG_T3,
+                        FIFF.FIFFV_COIL_NM_122,
                         FIFF.FIFFV_COIL_MAGNES_MAG,
                         FIFF.FIFFV_COIL_BABY_MAG),
                 megrefmag=(FIFF.FIFFV_COIL_KIT_REF_MAG,


Test patch:
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -144,7 +144,7 @@ jobs:
       uses: actions/cache@v3
       with:
         path: ${{ env.pythonLocation }}
-        key: test-0-${{ env.pythonLocation }}-${{ env.os }}-${{ hashFiles('setup.cfg') }}-${{ hashFiles('test_requirements.txt') }}
+        key: test-1-${{ env.pythonLocation }}-${{ env.os }}-${{ hashFiles('setup.cfg') }}-${{ hashFiles('test_requirements.txt') }}
 
     - name: Install Python dependencies using pip
       run: |
diff --git a/mne_bids/tests/test_write.py b/mne_bids/tests/test_write.py
--- a/mne_bids/tests/test_write.py
+++ b/mne_bids/tests/test_write.py
@@ -3897,3 +3897,22 @@ def test_unknown_extension(_bids_validate, tmp_path):
 
     write_raw_bids(raw, bids_path, allow_preload=True, format='FIF')
     _bids_validate(bids_root)
+
+
+@testing.requires_testing_data
+def test_write_neuromag122(_bids_validate, tmp_path):
+    """Test writing Neuromag122 data to BIDS."""
+    bids_root = tmp_path / 'bids'
+    raw_fname = data_path / 'MEG' / 'sample' / 'sample_audvis_trunc_raw.fif'
+    raw = mne.io.read_raw_fif(raw_fname, allow_maxshield=True)
+    raw.info["line_freq"] = 50  # power line frequency as required by BIDS
+    raw.pick('mag')
+    for c in raw.info['chs']:
+        c['coil_type'] = FIFF.FIFFV_COIL_NM_122
+
+    bids_path = BIDSPath(subject="01", task="wordreport", run="01",
+                         root=bids_root,
+                         extension=".fif", datatype="meg")
+    write_raw_bids(raw, bids_path, overwrite=True, allow_preload=True,
+                   format="FIF")
+    _bids_validate(bids_root)