Repository: mne-tools/mne-bids

Issue:
Write out combined EEG and iEEG recordings
#### Describe the problem
Currently, as far as I know, it is not possible to write out a file when there are both EEG and iEEG channels in the recording. MNE-BIDS throws an error and so I have to set EEG channels to "misc" to be able to still write the files. ("ValueError: Both EEG and iEEG channels found in data. There is currently no specification on how to handle this data. Please proceed manually.")
I know that this has probably been discussed before and that the issue likely stems from the fact that multimodal recordings are not clearly defined in BIDS, but I don't really see a reason why it shouldn't be possible to store multimodal data in the same file. 

#### Describe your solution
Maybe it would be possible to let the user decide by setting the parameter datatype to either eeg or ieeg.
If this is not set, we could infer the datatype from the more prevalent channel type.



Discussion:
How would you store the raw file? Do you want to store it in EEG folder or iEEG or split it into the two folders?
We simultaneously record subcortical LFP and cortical EEG signals (same front end, same processor) and so the data should definitely be stored in the same file. I would like to store it all in an iEEG folder, as the iEEG data is the more important one for us. What do you think? Currently we are indirectly being forced to either split the data from the same recording into two files (which itself is already kind of a violation of the BIDS standard for raw data right?), or to assign a false channel type to either the EEG or the iEEG channels.
I seem to remember a discussion [on the bids-specification github](https://github.com/bids-standard/bids-specification/issues/86). You might want to look into it ... it might have some hints what is the consensus etc.

@jasmainak  Thanks for the link! This discussion super interesting and relevant for us, because we are also simultaneously recording MEG and iEEG data, which are then stored in **separate** files and the "SimultaneousRecording" parameter could tell us which files were recorded at the same time. However, the issue I was describing ist somewhat different, because in my case, the EEG and iEEG data is recorded with the same hardware and stored in exactly the **same** file. And the consensus in the issue you posted seems to be that these should be stored in the same data file and then the sidecar files (e.g. "_ieeg.json") will tell you whether there are EEG and iEEG channels in the same file. So I think there should definitely be an option to store EEG and iEEG data in the same file, if they were recorded together, but maybe I am mistaken.
I see! I just wanted to share the pointer as you might find the answer what's the right thing to do. I agree that it sounds like we need a PR to mne-bids. Do you want to contribute? I'm sure @hoechenberger or @adam2392 or @sappelhoff might be able to help if you can't!
I think I would just handle this as a pure ieeg dataset that just happens to have some EEG channels (these are actually ECOG channels if I get it correctly), so +1 to extend mne-bids here.
@sappelhoff  Actually no these are really EEG channels :) ECOG channels don't pose a problem, as they are also iEEG channels (like LFP/sEEG/DBS channels). But yes, I definitely share your opinion that the iEEG channels (ECOG or LFP/sEEG/DBS) are more important, so I would agree in treating this like an iEEG dataset - that happen to have additional EEG channels.
@jasmainak  I would be very happy to contribute, but I might need some guidance as I'm not familiar with the details of what is happening under the MNE-BIDS hood. So when calling write_raw_bids, MNE-BIDS checks what types of channels are inside the recording and then infers the type of dataset right? If we detect both EEG and anyone of LFP/DBS/SEEG channel types, we would treat the dataset like iEEG data and set the datatype to "ieeg" right? I think this is the only case I ran into an Error with.
> cortical EEG signals

just to clarify for me: did you record EEG on the scalp, or directly on the brain / below the skull? :-D
@sappelhoff  Haha, yes we record EEG on the scalp and simultaneously LFP (DBS) signals. But you are right that sometimes we also record ECOG (subdural) additionally, so then we have LFP + ECOG + scalp EEG in the same recording.
@richardkoehler the automatic inference is an artifact of the time `BIDSPath` didn't exist. I think it needs to be made smarter now. My sense is that you `_handle_dataype` should be more like `_check_datatype` taking `datatype` as an argument and throwing an error if the datatype specified by the user doesn't exist in the data. Otherwise, the user should be trusted to know what they are doing if there are multiple data types and no automatic guessing done. Sounds reasonable @hoechenberger ?
@jasmainak  Okay that's super interesting to know. Then I would say it is definitely time to change this now :) I also agree with the notion that the datatype should be specified by the user and no assumptions should be made by MNE-BIDS.  
Give it a shot and we'll review it :)

Resolving patch:
diff --git a/mne_bids/utils.py b/mne_bids/utils.py
--- a/mne_bids/utils.py
+++ b/mne_bids/utils.py
@@ -89,22 +89,67 @@ def _get_ch_type_mapping(fro='mne', to='bids'):
     return mapping
 
 
-def _handle_datatype(raw):
-    """Get datatype."""
-    if 'eeg' in raw and ('ecog' in raw or 'seeg' in raw):
-        raise ValueError('Both EEG and iEEG channels found in data.'
-                         'There is currently no specification on how'
-                         'to handle this data. Please proceed manually.')
-    elif 'meg' in raw:
-        datatype = 'meg'
-    elif 'ecog' in raw or 'seeg' in raw:
-        datatype = 'ieeg'
-    elif 'eeg' in raw:
-        datatype = 'eeg'
+def _handle_datatype(raw, datatype, verbose=True):
+    """Check if datatype exists in raw object or infer datatype if possible.
+
+    Parameters
+    ----------
+    raw : mne.io.Raw
+        Raw object.
+    datatype : str | None
+        Can be one of either ``'meg'``, ``'eeg'``, or ``'ieeg'``. If ``None``,
+        `mne.utils._handle_datatype()` will attempt to infer the datatype from
+        the ``raw`` object. In case of multiple data types in the ``raw``
+        object, ``datatype`` must not be ``None``.
+    verbose : bool
+        If ``True``, this will print additional information in the case of
+        combined MEG and iEEG/EEG recordings.
+
+    Returns
+    -------
+    datatype : str
+        One of either ``'meg'``, ``'eeg'``, or ``'ieeg'``.
+    """
+    if datatype is not None:
+        _check_datatype(raw, datatype)
+        # MEG data is not supported by BrainVision or EDF files
+        if datatype in ['eeg', 'ieeg'] and 'meg' in raw:
+            if verbose:
+                print(os.linesep + f"Both {datatype} and 'meg' data found. "
+                                   f"BrainVision and EDF do not support 'meg' "
+                                   f"data. The data will therefore be stored "
+                                   f"as 'meg' data. If you wish to store your "
+                                   f"{datatype} data in BrainVision or EDF, "
+                                   f"please remove the 'meg' channels from "
+                                   f"your recording." + os.linesep)
+            datatype = 'meg'
     else:
-        raise ValueError('Neither MEG/EEG/iEEG channels found in data.'
-                         'Please use raw.set_channel_types to set the '
-                         'channel types in the data.')
+        datatypes = list()
+        ieeg_types = ['seeg', 'ecog']
+        if any(ieeg_type in raw for ieeg_type in ieeg_types):
+            datatypes.append('ieeg')
+        if 'meg' in raw:
+            datatypes.append('meg')
+        if 'eeg' in raw:
+            datatypes.append('eeg')
+        if len(datatypes) == 0:
+            raise ValueError('No MEG, EEG or iEEG channels found in data. '
+                             'Please use raw.set_channel_types to set the '
+                             'channel types in the data.')
+        elif len(datatypes) > 1:
+            if 'meg' in datatypes and 'ieeg' not in datatypes:
+                datatype = 'meg'
+            elif 'ieeg' in datatypes and 'meg' not in datatypes:
+                datatype = 'ieeg'
+            else:
+                raise ValueError(f'Multiple data types (``{datatypes}``) were '
+                                 'found in the data. Please specify the '
+                                 'datatype using '
+                                 '`bids_path.update(datatype="<datatype>")` '
+                                 'or use raw.set_channel_types to set the '
+                                 'correct channel types in the raw object.')
+        else:
+            datatype = datatypes[0]
     return datatype
 
 
@@ -385,3 +430,42 @@ def _stamp_to_dt(utc_stamp):
         stamp.append(0)
     return (datetime.fromtimestamp(0, tz=timezone.utc) +
             timedelta(0, stamp[0], stamp[1]))  # day, sec, μs
+
+
+def _check_datatype(raw, datatype):
+    """Check if datatype exists in given raw object.
+
+    Parameters
+    ----------
+    raw : mne.io.Raw
+        Raw object.
+    datatype : str
+        Can be one of either ``'meg'``, ``'eeg'``, or ``'ieeg'``.
+
+    Returns
+    -------
+    None
+    """
+    supported_types = ('meg', 'eeg', 'ieeg')
+    if datatype not in supported_types:
+        raise ValueError(
+            f'The specified datatype {datatype} is currently not supported. '
+            f'It should be one of  either `meg`, `eeg` or `ieeg` (Got '
+            f'`{datatype}`. Please specify a valid datatype using '
+            f'`bids_path.update(datatype="<datatype>")`.')
+    datatype_matches = False
+    if datatype == 'eeg' and datatype in raw:
+        datatype_matches = True
+    elif datatype == 'meg' and datatype in raw:
+        datatype_matches = True
+    elif datatype == 'ieeg':
+        ieeg_types = ('seeg', 'ecog')
+        if any(ieeg_type in raw for ieeg_type in ieeg_types):
+            datatype_matches = True
+    if not datatype_matches:
+        raise ValueError(
+            f'The specified datatype {datatype} was not found in the raw '
+            'object. Please specify the correct datatype using '
+            '`bids_path.update(datatype="<datatype>")` or use '
+            'raw.set_channel_types to set the correct channel types in '
+            'the raw object.')
diff --git a/mne_bids/write.py b/mne_bids/write.py
--- a/mne_bids/write.py
+++ b/mne_bids/write.py
@@ -34,8 +34,8 @@
 from mne_bids.dig import _write_dig_bids, _write_coordsystem_json
 from mne_bids.utils import (_write_json, _write_tsv, _write_text,
                             _age_on_date, _infer_eeg_placement_scheme,
-                            _handle_datatype, _get_ch_type_mapping,
-                            _check_anonymize, _stamp_to_dt)
+                            _get_ch_type_mapping, _check_anonymize,
+                            _stamp_to_dt, _handle_datatype)
 from mne_bids import BIDSPath
 from mne_bids.path import _parse_ext, _mkdir_p, _path_to_str
 from mne_bids.copyfiles import (copyfile_brainvision, copyfile_eeglab,
@@ -970,7 +970,8 @@ def write_raw_bids(raw, bids_path, events_data=None,
         The file to write. The `mne_bids.BIDSPath` instance passed here
         **must** have the ``.root`` attribute set. If the ``.datatype``
         attribute is not set, it will be inferred from the recording data type
-        found in ``raw``.
+        found in ``raw``. In case of multiple data types, the ``.datatype``
+        attribute must be set.
         Example::
 
             bids_path = BIDSPath(subject='01', session='01', task='testing',
@@ -993,9 +994,8 @@ def write_raw_bids(raw, bids_path, events_data=None,
             participants.tsv
             scans.tsv
 
-        Note that the data type is automatically inferred from the raw
-        object, as well as the extension. Data with MEG and other
-        electrophysiology data in the same file will be stored as ``'meg'``.
+        Note that the extension is automatically inferred from the raw
+        object.
     events_data : path-like | np.ndarray | None
         Use this parameter to specify events to write to the ``*_events.tsv``
         sidecar file, additionally to the object's `mne.Annotations` (which
@@ -1185,7 +1185,7 @@ def write_raw_bids(raw, bids_path, events_data=None,
                 'https://github.com/mne-tools/mne-bids/issues')
         raise ValueError(msg)
 
-    datatype = _handle_datatype(raw)
+    datatype = _handle_datatype(raw, bids_path.datatype, verbose)
     bids_path = bids_path.copy()
     bids_path = bids_path.update(
         datatype=datatype, suffix=datatype, extension=ext)
@@ -1330,7 +1330,7 @@ def write_raw_bids(raw, bids_path, events_data=None,
     # check if there is an BIDS-unsupported MEG format
     if bids_path.datatype == 'meg' and convert and not anonymize:
         raise ValueError(
-            f"Got file extension {convert} for MEG data, "
+            f"Got file extension {ext} for MEG data, "
             f"expected one of "
             f"{', '.join(sorted(ALLOWED_DATATYPE_EXTENSIONS['meg']))}")
 


Test patch:
diff --git a/mne_bids/tests/test_copyfiles.py b/mne_bids/tests/test_copyfiles.py
--- a/mne_bids/tests/test_copyfiles.py
+++ b/mne_bids/tests/test_copyfiles.py
@@ -21,7 +21,6 @@
 
 from mne.datasets import testing
 from mne_bids import BIDSPath
-from mne_bids.utils import _handle_datatype
 from mne_bids.path import _parse_ext
 
 from mne_bids.copyfiles import (_get_brainvision_encoding,
@@ -238,7 +237,8 @@ def test_copyfile_kit(tmpdir):
         raw_fname, mrk=hpi_fname, elp=electrode_fname,
         hsp=headshape_fname)
     _, ext = _parse_ext(raw_fname, verbose=True)
-    datatype = _handle_datatype(raw)
+
+    datatype = 'meg'  # copyfile_kit makes the same assumption
 
     bids_path = BIDSPath(
         subject=subject_id, session=session_id, run=run, acquisition=acq,
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
@@ -11,7 +11,7 @@
 from pathlib import Path
 
 import pytest
-from numpy.random import random
+from numpy.random import random, RandomState
 
 with warnings.catch_warnings():
     warnings.filterwarnings(action='ignore',
@@ -20,9 +20,9 @@
     import mne
 
 from mne_bids import BIDSPath
-from mne_bids.utils import (_check_types, _age_on_date,
-                            _infer_eeg_placement_scheme, _handle_datatype,
-                            _get_ch_type_mapping)
+from mne_bids.utils import (_check_types, _age_on_date, _handle_datatype,
+                            _infer_eeg_placement_scheme, _get_ch_type_mapping,
+                            _check_datatype)
 from mne_bids.path import _path_to_str
 
 base_path = op.join(op.dirname(mne.__file__), 'io')
@@ -46,29 +46,49 @@ def test_get_ch_type_mapping():
 def test_handle_datatype():
     """Test the automatic extraction of datatype from the data."""
     # Create a dummy raw
-    n_channels = 1
+    n_channels = 2
     sampling_rate = 100
     data = random((n_channels, sampling_rate))
-    channel_types = ['grad', 'eeg', 'ecog']
-    expected_modalities = ['meg', 'eeg', 'ieeg']
-    # do it once for each type ... and once for "no type"
-    for chtype, datatype in zip(channel_types, expected_modalities):
-        info = mne.create_info(n_channels, sampling_rate, ch_types=[chtype])
+    # datatype is given, check once for each datatype
+    channel_types = ['grad', 'eeg', 'ecog', 'seeg']
+    datatypes = ['meg', 'eeg', 'ieeg', 'ieeg']
+    for ch_type, datatype in zip(channel_types, datatypes):
+        info = mne.create_info(n_channels, sampling_rate,
+                               ch_types=[ch_type] * 2)
         raw = mne.io.RawArray(data, info)
-        assert _handle_datatype(raw) == datatype
-
-    # if the situation is ambiguous (EEG and iEEG channels both), raise error
-    with pytest.raises(ValueError, match='Both EEG and iEEG channels found'):
-        info = mne.create_info(2, sampling_rate,
-                               ch_types=['eeg', 'ecog'])
+        assert _handle_datatype(raw, datatype) == datatype
+    # datatype is not given, will be inferred if possible
+    datatype = None
+    # check if datatype is correctly inferred (combined EEG and iEEG/MEG data)
+    channel_types = [['grad', 'eeg'], ['eeg', 'mag'], ['eeg', 'seeg'],
+                     ['ecog', 'eeg']]
+    expected_modalities = ['meg', 'meg', 'ieeg', 'ieeg']
+    for ch_type, expected_mod in zip(channel_types, expected_modalities):
+        info = mne.create_info(n_channels, sampling_rate, ch_types=ch_type)
         raw = mne.io.RawArray(random((2, sampling_rate)), info)
-        _handle_datatype(raw)
-
-    # if we cannot find a proper channel type, we raise an error
-    with pytest.raises(ValueError, match='Neither MEG/EEG/iEEG channels'):
-        info = mne.create_info(n_channels, sampling_rate, ch_types=['misc'])
+        assert _handle_datatype(raw, datatype) == expected_mod
+    # set type to MEG if type is EEG/iEEG but there are MEG channels as well
+    channel_types = [['grad', 'eeg'], ['grad', 'seeg']]
+    datatypes = ['eeg', 'ieeg']
+    for ch_type, datatype in zip(channel_types, datatypes):
+        info = mne.create_info(n_channels, sampling_rate, ch_types=ch_type)
+        raw = mne.io.RawArray(random((2, sampling_rate)), info)
+        assert _handle_datatype(raw, datatype) == 'meg'
+    # if the situation is ambiguous (iEEG and MEG), raise ValueError
+    datatype = None
+    channel_types = [['grad', 'ecog'], ['grad', 'seeg']]
+    for ch_type in channel_types:
+        with pytest.raises(ValueError, match='Multiple data types'):
+            info = mne.create_info(n_channels, sampling_rate, ch_types=ch_type)
+            raw = mne.io.RawArray(random((2, sampling_rate)), info)
+            _handle_datatype(raw, datatype)
+    # if proper channel type (iEEG, EEG or MEG) is not found, raise ValueError
+    ch_type = ['misc']
+    with pytest.raises(ValueError, match='No MEG, EEG or iEEG channels found'):
+        info = mne.create_info(n_channels, sampling_rate,
+                               ch_types=ch_type * 2)
         raw = mne.io.RawArray(data, info)
-        _handle_datatype(raw)
+        _handle_datatype(raw, datatype)
 
 
 def test_check_types():
@@ -124,3 +144,31 @@ def test_infer_eeg_placement_scheme():
     raw.rename_channels({'P3': 'foo'})
     placement_scheme = _infer_eeg_placement_scheme(raw)
     assert placement_scheme == 'n/a'
+
+
+def test_check_datatype():
+    """Test checking if datatype exists in raw data."""
+    sfreq, n_points = 1024., int(1e6)
+    rng = RandomState(99)
+    info_eeg = mne.create_info(['ch1', 'ch2', 'ch3'], sfreq, ['eeg'] * 3)
+    raw_eeg = mne.io.RawArray(rng.random((3, n_points)) * 1e-6, info_eeg)
+    info_meg = mne.create_info(['ch1', 'ch2', 'ch3'], sfreq, ['mag'] * 3)
+    raw_meg = mne.io.RawArray(rng.random((3, n_points)) * 1e-6, info_meg)
+    info_ieeg = mne.create_info(['ch1', 'ch2', 'ch3'], sfreq, ['seeg'] * 3)
+    raw_ieeg = mne.io.RawArray(rng.random((3, n_points)) * 1e-6, info_ieeg)
+    # check behavior for unsupported data types
+    for datatype in (None, 'anat'):
+        with pytest.raises(ValueError, match=f'The specified datatype '
+                                             f'{datatype} is currently not'):
+            _check_datatype(raw_eeg, datatype)
+    # check behavior for matching data type
+    for raw, datatype in [(raw_eeg, 'eeg'), (raw_meg, 'meg'),
+                          (raw_ieeg, 'ieeg')]:
+        _check_datatype(raw, datatype)
+    # check for missing data type
+    for raw, datatype in [(raw_ieeg, 'eeg'), (raw_meg, 'eeg'),
+                          (raw_ieeg, 'meg'), (raw_eeg, 'meg'),
+                          (raw_meg, 'ieeg'), (raw_eeg, 'ieeg')]:
+        with pytest.raises(ValueError, match=f'The specified datatype '
+                                             f'{datatype} was not found'):
+            _check_datatype(raw, datatype)
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
@@ -450,6 +450,7 @@ def test_fif(_bids_validate, tmpdir):
 
     epochs = mne.Epochs(raw2, events, event_id=event_id, tmin=-0.2, tmax=0.5,
                         preload=True)
+    bids_path = bids_path.update(datatype='eeg')
     with pytest.warns(RuntimeWarning,
                       match='Converting data files to BrainVision format'):
         write_raw_bids(raw2, bids_path,
@@ -505,13 +506,14 @@ def test_fif(_bids_validate, tmpdir):
 
     # give the raw object some fake participant data (potentially overwriting)
     raw = _read_raw_fif(raw_fname)
-    write_raw_bids(raw, bids_path, events_data=events,
+    bids_path_meg = bids_path.copy().update(datatype='meg')
+    write_raw_bids(raw, bids_path_meg, events_data=events,
                    event_id=event_id, overwrite=True)
 
     # try and write preloaded data
     raw = _read_raw_fif(raw_fname, preload=True)
     with pytest.raises(ValueError, match='preloaded'):
-        write_raw_bids(raw, bids_path, events_data=events,
+        write_raw_bids(raw, bids_path_meg, events_data=events,
                        event_id=event_id, overwrite=False)
 
     # test anonymize
@@ -527,7 +529,7 @@ def test_fif(_bids_validate, tmpdir):
     with open(readme, 'w', encoding='utf-8-sig') as fid:
         fid.write('Welcome to my dataset\n')
 
-    bids_path2 = bids_path.copy().update(subject=subject_id2)
+    bids_path2 = bids_path_meg.copy().update(subject=subject_id2)
     raw = _read_raw_fif(raw_fname2)
     bids_output_path = write_raw_bids(raw, bids_path2,
                                       events_data=events,
@@ -604,6 +606,7 @@ def test_fif(_bids_validate, tmpdir):
         write_raw_bids(raw, bids_path)
 
     raw = _read_raw_fif(raw_fname)
+    bids_path = bids_path.copy().update(datatype='meg')
     write_raw_bids(raw, bids_path, events_data=events, event_id=event_id,
                    overwrite=True)
 
@@ -979,7 +982,7 @@ def test_vhdr(_bids_validate, tmpdir):
     raw.set_channel_types({raw.ch_names[i]: 'ecog'
                            for i in mne.pick_types(raw.info, eeg=True)})
     bids_root = tmpdir.mkdir('bids2')
-    bids_path.update(root=bids_root)
+    bids_path.update(root=bids_root, datatype='ieeg')
     write_raw_bids(raw, bids_path, overwrite=False)
     _bids_validate(bids_root)
 
@@ -995,7 +998,7 @@ def test_vhdr(_bids_validate, tmpdir):
 
     # convert to BIDS
     bids_root = tmpdir.mkdir('bids3')
-    bids_path.update(root=bids_root)
+    bids_path.update(root=bids_root, datatype='eeg')
     write_raw_bids(raw, bids_path)
 
     # check impedances
@@ -1232,7 +1235,7 @@ def test_eegieeg(dir_name, fname, reader, _bids_validate, tmpdir):
     ieeg_raw.set_channel_types({raw.ch_names[i]: 'ecog'
                                 for i in eeg_picks})
     bids_root = tmpdir.mkdir('bids2')
-    bids_path.update(root=bids_root)
+    bids_path.update(root=bids_root, datatype='ieeg')
     kwargs = dict(raw=ieeg_raw, bids_path=bids_path, overwrite=True)
     if dir_name == 'EDF':
         write_raw_bids(**kwargs)
@@ -1264,7 +1267,7 @@ def test_eegieeg(dir_name, fname, reader, _bids_validate, tmpdir):
                                                  coord_frame='mni_tal')
     ieeg_raw.set_montage(ecog_montage)
     bids_root = tmpdir.mkdir('bids3')
-    bids_path.update(root=bids_root)
+    bids_path.update(root=bids_root, datatype='ieeg')
     kwargs = dict(raw=ieeg_raw, bids_path=bids_path, overwrite=True)
     if dir_name == 'EDF':
         write_raw_bids(**kwargs)
@@ -1297,7 +1300,7 @@ def test_eegieeg(dir_name, fname, reader, _bids_validate, tmpdir):
     # test anonymize and convert
     if check_version('pybv', '0.4') or dir_name == 'EDF':
         raw = reader(raw_fname)
-
+        bids_path.update(root=bids_root, datatype='eeg')
         kwargs = dict(raw=raw, bids_path=bids_path, overwrite=True)
         if dir_name == 'NihonKohden':
             with pytest.warns(RuntimeWarning,
@@ -1325,7 +1328,7 @@ def test_bdf(_bids_validate, tmpdir):
     data_path = op.join(base_path, 'edf', 'tests', 'data')
     raw_fname = op.join(data_path, 'test.bdf')
 
-    bids_path = _bids_path.copy().update(root=tmpdir)
+    bids_path = _bids_path.copy().update(root=tmpdir, datatype='eeg')
 
     raw = _read_raw_bdf(raw_fname)
     raw.info['line_freq'] = 60
@@ -1358,7 +1361,6 @@ def test_bdf(_bids_validate, tmpdir):
     # Now read the raw data back from BIDS, with the tampered TSV, to show
     # that the channels.tsv truly influences how read_raw_bids sets ch_types
     # in the raw data object
-    bids_path.update(datatype='eeg')
     raw = read_raw_bids(bids_path=bids_path)
     assert coil_type(raw.info, test_ch_idx) == 'misc'
     with pytest.raises(TypeError, match="unexpected keyword argument 'foo'"):
@@ -1425,7 +1427,7 @@ def test_set(_bids_validate, tmpdir):
     raw.set_channel_types({raw.ch_names[i]: 'ecog'
                            for i in mne.pick_types(raw.info, eeg=True)})
     bids_root = tmpdir.mkdir('bids2')
-    bids_path.update(root=bids_root)
+    bids_path.update(root=bids_root, datatype='ieeg')
     write_raw_bids(raw, bids_path)
     _bids_validate(bids_root)
 
@@ -2402,7 +2404,7 @@ def test_anonymize(subject, dir_name, fname, reader, tmpdir):
         bids_path.update(task='noise', session=raw_date,
                          suffix='meg', datatype='meg')
     else:
-        bids_path.update(suffix='ieeg', datatype='ieeg')
+        bids_path.update(suffix='eeg', datatype='eeg')
     daysback_min, daysback_max = get_anonymization_daysback(raw)
     anonymize = dict(daysback=daysback_min + 1)
     bids_path = \
@@ -2539,7 +2541,7 @@ def test_error_write_meg_as_eeg(dir_name, fname, reader, tmpdir):
     bids_path = _bids_path.copy().update(root=bids_root, datatype='eeg',
                                          extension='.vhdr')
     raw = reader(raw_fname)
-    kwargs = dict(raw=raw, bids_path=bids_path)
+    kwargs = dict(raw=raw, bids_path=bids_path.update(datatype='meg'))
 
     # if we accidentally add MEG channels, then an error will occur
     raw.set_channel_types({raw.info['ch_names'][0]: 'mag'})
@@ -2646,7 +2648,10 @@ def test_write_extension_case_insensitive(_bids_validate, tmpdir, datatype):
     os.rename(raw_fname, new_raw_fname)
 
     # the BIDS path for test datasets to get written to
-    bids_path = _bids_path.copy().update(root=bids_root, datatype=datatype)
-
     raw = reader(new_raw_fname)
+    bids_path = _bids_path.copy().update(root=bids_root, datatype='eeg')
+    write_raw_bids(raw, bids_path)
+    raw.set_channel_types({raw.ch_names[i]: 'ecog'
+                           for i in mne.pick_types(raw.info, eeg=True)})
+    bids_path = _bids_path.copy().update(root=bids_root, datatype='ieeg')
     write_raw_bids(raw, bids_path)