Repository: mne-tools/mne-bids

Issue:
Support new channel type "DBS"
#### Describe the problem
In Version 0.23.0 of MNE, support for the channel type DBS for Deep Brain Stimulation recordings was added (https://mne.tools/stable/whats_new.html#version-0-23-0), so it would likely be desirable to add support for writing and reading data with MNE-BIDS as well.

#### Describe your solution
I implemented the support in a branch and made a pull request with the number #800 

In the sidecar _ieeg.json file, DBS channels are not counted separately but counted together with SEEG Channels in "SEEGChannelCount", as specified in BIDS: "SEEGChannelCount": "Number of iEEG depth channels included in the recording..." (https://bids-specification.readthedocs.io/en/stable/04-modality-specific-files/04-intracranial-electroencephalography.html#sidecar-json-_ieegjson)




Discussion:

Resolving patch:
diff --git a/mne_bids/utils.py b/mne_bids/utils.py
--- a/mne_bids/utils.py
+++ b/mne_bids/utils.py
@@ -67,7 +67,7 @@ def _get_ch_type_mapping(fro='mne', to='bids'):
     if fro == 'mne' and to == 'bids':
         mapping = dict(eeg='EEG', misc='MISC', stim='TRIG', emg='EMG',
                        ecog='ECOG', seeg='SEEG', eog='EOG', ecg='ECG',
-                       resp='RESP', bio='MISC',
+                       resp='RESP', bio='MISC', dbs='DBS',
                        # MEG channels
                        meggradaxial='MEGGRADAXIAL', megmag='MEGMAG',
                        megrefgradaxial='MEGREFGRADAXIAL',
@@ -80,7 +80,7 @@ def _get_ch_type_mapping(fro='mne', to='bids'):
                        RESP='resp',
                        # No MEG channels for now
                        # Many to one mapping
-                       VEOG='eog', HEOG='eog')
+                       VEOG='eog', HEOG='eog', DBS='dbs')
     else:
         raise ValueError('Only two types of mappings are currently supported: '
                          'from mne to bids, or from bids to mne. However, '
@@ -125,7 +125,7 @@ def _handle_datatype(raw, datatype, verbose=True):
             datatype = 'meg'
     else:
         datatypes = list()
-        ieeg_types = ['seeg', 'ecog']
+        ieeg_types = ['seeg', 'ecog', 'dbs']
         if any(ieeg_type in raw for ieeg_type in ieeg_types):
             datatypes.append('ieeg')
         if 'meg' in raw:
@@ -459,7 +459,7 @@ def _check_datatype(raw, datatype):
     elif datatype == 'meg' and datatype in raw:
         datatype_matches = True
     elif datatype == 'ieeg':
-        ieeg_types = ('seeg', 'ecog')
+        ieeg_types = ('seeg', 'ecog', 'dbs')
         if any(ieeg_type in raw for ieeg_type in ieeg_types):
             datatype_matches = True
     if not datatype_matches:
diff --git a/mne_bids/write.py b/mne_bids/write.py
--- a/mne_bids/write.py
+++ b/mne_bids/write.py
@@ -94,7 +94,8 @@ def _channels_tsv(raw, fname, overwrite=False, verbose=True):
                     emg='ElectroMyoGram',
                     misc='Miscellaneous',
                     bio='Biological',
-                    ias='Internal Active Shielding')
+                    ias='Internal Active Shielding',
+                    dbs='Deep Brain Stimulation')
     get_specific = ('mag', 'ref_meg', 'grad')
 
     # get the manufacturer from the file in the Raw object
@@ -643,6 +644,8 @@ def _sidecar_json(raw, task, manufacturer, fname, datatype,
                       if ch['kind'] == FIFF.FIFFV_MISC_CH])
     n_stimchan = len([ch for ch in raw.info['chs']
                       if ch['kind'] == FIFF.FIFFV_STIM_CH]) - n_ignored
+    n_dbschan = len([ch for ch in raw.info['chs']
+                     if ch['kind'] == FIFF.FIFFV_DBS_CH])
 
     # Set DigitizedLandmarks to True if any of LPA, RPA, NAS are found
     # Set DigitizedHeadPoints to True if any "Extra" points are found
@@ -723,8 +726,7 @@ def _sidecar_json(raw, task, manufacturer, fname, datatype,
     ch_info_json_ieeg = [
         ('iEEGReference', 'n/a'),
         ('ECOGChannelCount', n_ecogchan),
-        ('SEEGChannelCount', n_seegchan)]
-
+        ('SEEGChannelCount', n_seegchan + n_dbschan)]
     ch_info_ch_counts = [
         ('EEGChannelCount', n_eegchan),
         ('EOGChannelCount', n_eogchan),


Test patch:
diff --git a/mne_bids/tests/test_utils.py b/mne_bids/tests/test_utils.py
--- a/mne_bids/tests/test_utils.py
+++ b/mne_bids/tests/test_utils.py
@@ -50,8 +50,8 @@ def test_handle_datatype():
     sampling_rate = 100
     data = random((n_channels, sampling_rate))
     # datatype is given, check once for each datatype
-    channel_types = ['grad', 'eeg', 'ecog', 'seeg']
-    datatypes = ['meg', 'eeg', 'ieeg', 'ieeg']
+    channel_types = ['grad', 'eeg', 'ecog', 'seeg', 'dbs']
+    datatypes = ['meg', 'eeg', 'ieeg', 'ieeg', 'ieeg']
     for ch_type, datatype in zip(channel_types, datatypes):
         info = mne.create_info(n_channels, sampling_rate,
                                ch_types=[ch_type] * 2)
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
@@ -1035,6 +1035,15 @@ def test_vhdr(_bids_validate, tmpdir):
     write_raw_bids(raw, bids_path, overwrite=False)
     _bids_validate(bids_root)
 
+    # Now let's test that the same works for new channel type 'dbs'
+    raw = _read_raw_brainvision(raw_fname)
+    raw.set_channel_types({raw.ch_names[i]: 'dbs'
+                           for i in mne.pick_types(raw.info, eeg=True)})
+    bids_root = tmpdir.mkdir('bids_dbs')
+    bids_path.update(root=bids_root)
+    write_raw_bids(raw, bids_path, overwrite=False)
+    _bids_validate(bids_root)
+
     # Test coords and impedance writing
     # first read the data and set a montage
     data_path = op.join(testing.data_path(), 'montage')