Exemple #1
0
def test_line_freq_estimation():
    """Test estimating line frequency."""
    bids_root = _TempDir()

    # read in USA dataset, so it should find 50 Hz
    raw = mne.io.read_raw_fif(raw_fname)
    kind = "meg"

    # assert that we get the same line frequency set
    bids_fname = bids_basename.copy().update(suffix=f'{kind}.fif')

    # find sidecar JSON fname
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           bids_root,
                                           '{}.json'.format(kind),
                                           allow_fail=True)

    # 1. when nothing is set, default to use PSD estimation -> should be 60
    # for `sample` dataset
    raw.info['line_freq'] = None
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    _update_sidecar(sidecar_fname, "PowerLineFrequency", "n/a")
    with pytest.warns(RuntimeWarning, match="No line frequency found"):
        raw = read_raw_bids(bids_basename=bids_basename,
                            bids_root=bids_root,
                            kind=kind)
        assert raw.info['line_freq'] == 60

    # test that `somato` dataset finds 50 Hz (EU dataset)
    somato_raw = mne.io.read_raw_fif(somato_raw_fname)
    somato_raw.info['line_freq'] = None
    write_raw_bids(somato_raw, bids_basename, bids_root, overwrite=True)
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           bids_root,
                                           '{}.json'.format(kind),
                                           allow_fail=True)
    _update_sidecar(sidecar_fname, "PowerLineFrequency", "n/a")
    with pytest.warns(RuntimeWarning, match="No line frequency found"):
        somato_raw = read_raw_bids(bids_basename=bids_basename,
                                   bids_root=bids_root,
                                   kind=kind)
        assert somato_raw.info['line_freq'] == 50

    # assert that line_freq should be None when
    # all picks are not meg/eeg/ecog/seeg
    somato_raw.info['line_freq'] = None
    somato_raw.set_channel_types({
        somato_raw.ch_names[i]: 'bio'
        for i in range(len(somato_raw.ch_names))
    })
    somato_raw = _handle_info_reading(sidecar_fname, somato_raw, verbose=True)
    assert somato_raw.info['line_freq'] is None
Exemple #2
0
def _update_electrodes_json(electrodes_json_fpath, **kwargs):
    electrodes_json_fpath = Path(electrodes_json_fpath)
    if not electrodes_json_fpath.exists():
        electrodes_json_fpath.parent.mkdir(parents=True, exist_ok=True)
        with open(electrodes_json_fpath, "w") as fout:
            sidecar_json = json.dump(kwargs, fout)
    else:
        for key, val in kwargs.items():
            _update_sidecar(electrodes_json_fpath, key, val)
        with open(electrodes_json_fpath, "r") as fin:
            sidecar_json = json.load(fin)
    return sidecar_json
Exemple #3
0
def test_handle_info_reading():
    """Test reading information from a BIDS sidecar.json file."""
    bids_root = _TempDir()

    # read in USA dataset, so it should find 50 Hz
    raw = _read_raw_fif(raw_fname)

    # write copy of raw with line freq of 60
    # bids basename and fname
    bids_path = BIDSPath(subject='01',
                         session='01',
                         task='audiovisual',
                         run='01',
                         root=bids_root)
    suffix = "meg"
    bids_fname = bids_path.copy().update(suffix=suffix, extension='.fif')
    write_raw_bids(raw, bids_path, overwrite=True)

    # find sidecar JSON fname
    bids_fname.update(datatype=suffix)
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           suffix=suffix,
                                           extension='.json')

    # assert that we get the same line frequency set
    raw = read_raw_bids(bids_path=bids_path)
    assert raw.info['line_freq'] == 60

    # 2. if line frequency is not set in raw file, then ValueError
    raw.info['line_freq'] = None
    with pytest.raises(ValueError, match="PowerLineFrequency .* required"):
        write_raw_bids(raw, bids_path, overwrite=True)

    # make a copy of the sidecar in "derivatives/"
    # to check that we make sure we always get the right sidecar
    # in addition, it should not break the sidecar reading
    # in `read_raw_bids`
    deriv_dir = op.join(bids_root, "derivatives")
    sidecar_copy = op.join(deriv_dir, op.basename(sidecar_fname))
    os.mkdir(deriv_dir)
    with open(sidecar_fname, "r") as fin:
        sidecar_json = json.load(fin)
        sidecar_json["PowerLineFrequency"] = 45
    _write_json(sidecar_copy, sidecar_json)
    raw = read_raw_bids(bids_path=bids_path)
    assert raw.info['line_freq'] == 60

    # 3. assert that we get an error when sidecar json doesn't match
    _update_sidecar(sidecar_fname, "PowerLineFrequency", 55)
    with pytest.raises(ValueError, match="Line frequency in sidecar json"):
        raw = read_raw_bids(bids_path=bids_path)
        assert raw.info['line_freq'] == 55
Exemple #4
0
def test_handle_info_reading():
    """Test reading information from a BIDS sidecar.json file."""
    bids_root = _TempDir()

    # read in USA dataset, so it should find 50 Hz
    raw = mne.io.read_raw_fif(raw_fname)
    raw.info['line_freq'] = 60

    # write copy of raw with line freq of 60
    # bids basename and fname
    bids_basename = make_bids_basename(subject='01',
                                       session='01',
                                       task='audiovisual',
                                       run='01')
    kind = "meg"
    bids_fname = bids_basename + '_{}.fif'.format(kind)
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)

    # find sidecar JSON fname
    sidecar_fname = _find_matching_sidecar(bids_fname,
                                           bids_root,
                                           '{}.json'.format(kind),
                                           allow_fail=True)

    # assert that we get the same line frequency set
    raw = mne_bids.read_raw_bids(bids_fname, bids_root)
    assert raw.info['line_freq'] == 60

    # 2. if line frequency is not set in raw file, then default to sidecar
    raw.info['line_freq'] = None
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    _update_sidecar(sidecar_fname, "PowerLineFrequency", 55)
    raw = mne_bids.read_raw_bids(bids_fname, bids_root)
    assert raw.info['line_freq'] == 55

    # make a copy of the sidecar in "derivatives/"
    # to check that we make sure we always get the right sidecar
    # in addition, it should not break the sidecar reading
    # in `read_raw_bids`
    deriv_dir = op.join(bids_root, "derivatives")
    sidecar_copy = op.join(deriv_dir, op.basename(sidecar_fname))
    os.mkdir(deriv_dir)
    with open(sidecar_fname, "r") as fin:
        sidecar_json = json.load(fin)
        sidecar_json["PowerLineFrequency"] = 45
    _write_json(sidecar_copy, sidecar_json)
    raw = mne_bids.read_raw_bids(bids_fname, bids_root)
    assert raw.info['line_freq'] == 55

    # 3. if line frequency is set in raw file, but not sidecar
    raw.info['line_freq'] = 60
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    _update_sidecar(sidecar_fname, "PowerLineFrequency", "n/a")
    raw = mne_bids.read_raw_bids(bids_fname, bids_root)
    assert raw.info['line_freq'] == 60

    # 4. assert that we get an error when sidecar json doesn't match
    _update_sidecar(sidecar_fname, "PowerLineFrequency", 55)
    with pytest.raises(ValueError, match="Line frequency in sidecar json"):
        raw = mne_bids.read_raw_bids(bids_fname, bids_root)
Exemple #5
0
def test_handle_ieeg_coords_reading(bids_basename):
    """Test reading iEEG coordinates from BIDS files."""
    bids_root = _TempDir()

    data_path = op.join(testing.data_path(), 'EDF')
    raw_fname = op.join(data_path, 'test_reduced.edf')
    bids_fname = bids_basename.copy().update(suffix='ieeg.edf')

    raw = mne.io.read_raw_edf(raw_fname)

    # ensure we are writing 'ecog'/'ieeg' data
    raw.set_channel_types({ch: 'ecog' for ch in raw.ch_names})

    # coordinate frames in mne-python should all map correctly
    # set a `random` montage
    ch_names = raw.ch_names
    elec_locs = np.random.random((len(ch_names), 3)).astype(float)
    ch_pos = dict(zip(ch_names, elec_locs))
    coordinate_frames = ['mri', 'ras']
    for coord_frame in coordinate_frames:
        # XXX: mne-bids doesn't support multiple electrodes.tsv files
        sh.rmtree(bids_root)
        montage = mne.channels.make_dig_montage(ch_pos=ch_pos,
                                                coord_frame=coord_frame)
        raw.set_montage(montage)
        write_raw_bids(raw,
                       bids_basename,
                       bids_root,
                       overwrite=True,
                       verbose=False)
        # read in raw file w/ updated coordinate frame
        # and make sure all digpoints are correct coordinate frames
        raw_test = read_raw_bids(bids_basename=bids_basename,
                                 bids_root=bids_root,
                                 verbose=False)
        coord_frame_int = MNE_STR_TO_FRAME[coord_frame]
        for digpoint in raw_test.info['dig']:
            assert digpoint['coord_frame'] == coord_frame_int

    # start w/ new bids root
    sh.rmtree(bids_root)
    write_raw_bids(raw,
                   bids_basename,
                   bids_root,
                   overwrite=True,
                   verbose=False)

    # obtain the sensor positions and assert ch_coords are same
    raw_test = read_raw_bids(bids_basename=bids_basename,
                             bids_root=bids_root,
                             verbose=False)
    orig_locs = raw.info['dig'][1]
    test_locs = raw_test.info['dig'][1]
    assert orig_locs == test_locs
    assert not object_diff(raw.info['chs'], raw_test.info['chs'])

    # read in the data and assert montage is the same
    # regardless of 'm', 'cm', 'mm', or 'pixel'
    scalings = {'m': 1, 'cm': 100, 'mm': 1000}
    coordsystem_fname = _find_matching_sidecar(bids_fname,
                                               bids_root,
                                               suffix='coordsystem.json',
                                               allow_fail=True)
    electrodes_fname = _find_matching_sidecar(bids_fname,
                                              bids_root,
                                              "electrodes.tsv",
                                              allow_fail=True)
    orig_electrodes_dict = _from_tsv(electrodes_fname,
                                     [str, float, float, float, str])

    # not BIDS specified should not be read
    coord_unit = 'km'
    scaling = 0.001
    _update_sidecar(coordsystem_fname, 'iEEGCoordinateUnits', coord_unit)
    electrodes_dict = _from_tsv(electrodes_fname,
                                [str, float, float, float, str])
    for axis in ['x', 'y', 'z']:
        electrodes_dict[axis] = \
            np.multiply(orig_electrodes_dict[axis], scaling)
    _to_tsv(electrodes_dict, electrodes_fname)
    with pytest.warns(RuntimeWarning,
                      match='Coordinate unit is not '
                      'an accepted BIDS unit'):
        raw_test = read_raw_bids(bids_basename=bids_basename,
                                 bids_root=bids_root,
                                 verbose=False)

    # correct BIDS units should scale to meters properly
    for coord_unit, scaling in scalings.items():
        # update coordinate SI units
        _update_sidecar(coordsystem_fname, 'iEEGCoordinateUnits', coord_unit)
        electrodes_dict = _from_tsv(electrodes_fname,
                                    [str, float, float, float, str])
        for axis in ['x', 'y', 'z']:
            electrodes_dict[axis] = \
                np.multiply(orig_electrodes_dict[axis], scaling)
        _to_tsv(electrodes_dict, electrodes_fname)

        # read in raw file w/ updated montage
        raw_test = read_raw_bids(bids_basename=bids_basename,
                                 bids_root=bids_root,
                                 verbose=False)

        # obtain the sensor positions and make sure they're the same
        assert_dig_allclose(raw.info, raw_test.info)

    # XXX: Improve by changing names to 'unknown' coordframe (needs mne PR)
    # check that coordinate systems other coordinate systems should be named
    # in the file and not the CoordinateSystem, which is reserved for keywords
    coordinate_frames = ['lia', 'ria', 'lip', 'rip', 'las']
    for coord_frame in coordinate_frames:
        # update coordinate units
        _update_sidecar(coordsystem_fname, 'iEEGCoordinateSystem', coord_frame)
        # read in raw file w/ updated coordinate frame
        # and make sure all digpoints are MRI coordinate frame
        with pytest.warns(RuntimeWarning,
                          match="iEEG Coordinate frame is "
                          "not accepted BIDS keyword"):
            raw_test = read_raw_bids(bids_basename=bids_basename,
                                     bids_root=bids_root,
                                     verbose=False)
            assert raw_test.info['dig'] is None

    # ACPC should be read in as RAS for iEEG
    _update_sidecar(coordsystem_fname, 'iEEGCoordinateSystem', 'acpc')
    raw_test = read_raw_bids(bids_basename=bids_basename,
                             bids_root=bids_root,
                             verbose=False)
    coord_frame_int = MNE_STR_TO_FRAME['ras']
    for digpoint in raw_test.info['dig']:
        assert digpoint['coord_frame'] == coord_frame_int

    # test error message if electrodes don't match
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    electrodes_dict = _from_tsv(electrodes_fname)
    # pop off 5 channels
    for key in electrodes_dict.keys():
        for i in range(5):
            electrodes_dict[key].pop()
    _to_tsv(electrodes_dict, electrodes_fname)
    with pytest.raises(RuntimeError, match='Channels do not correspond'):
        raw_test = read_raw_bids(bids_basename=bids_basename,
                                 bids_root=bids_root,
                                 verbose=False)

    # make sure montage is set if there are coordinates w/ 'n/a'
    raw.info['bads'] = []
    write_raw_bids(raw,
                   bids_basename,
                   bids_root,
                   overwrite=True,
                   verbose=False)
    electrodes_dict = _from_tsv(electrodes_fname)
    for axis in ['x', 'y', 'z']:
        electrodes_dict[axis][0] = 'n/a'
        electrodes_dict[axis][3] = 'n/a'
    _to_tsv(electrodes_dict, electrodes_fname)

    # test if montage is correctly set via mne-bids
    # electrode coordinates should be nan
    # when coordinate is 'n/a'
    nan_chs = [electrodes_dict['name'][i] for i in [0, 3]]
    with pytest.warns(RuntimeWarning,
                      match='There are channels '
                      'without locations'):
        raw = read_raw_bids(bids_basename=bids_basename,
                            bids_root=bids_root,
                            verbose=False)
        for idx, ch in enumerate(raw.info['chs']):
            if ch['ch_name'] in nan_chs:
                assert all(np.isnan(ch['loc'][:3]))
            else:
                assert not any(np.isnan(ch['loc'][:3]))
            assert ch['ch_name'] not in raw.info['bads']
Exemple #6
0
def test_handle_eeg_coords_reading():
    """Test reading iEEG coordinates from BIDS files."""
    bids_root = _TempDir()

    data_path = op.join(testing.data_path(), 'EDF')
    raw_fname = op.join(data_path, 'test_reduced.edf')
    raw = mne.io.read_raw_edf(raw_fname)

    # ensure we are writing 'eeg' data
    raw.set_channel_types({ch: 'eeg' for ch in raw.ch_names})

    # set a `random` montage
    ch_names = raw.ch_names
    elec_locs = np.random.random((len(ch_names), 3)).astype(float)
    ch_pos = dict(zip(ch_names, elec_locs))

    # # create montage in 'unknown' coordinate frame
    # # and assert coordsystem/electrodes sidecar tsv don't exist
    montage = mne.channels.make_dig_montage(ch_pos=ch_pos,
                                            coord_frame="unknown")
    raw.set_montage(montage)
    with pytest.warns(RuntimeWarning, match="Skipping EEG electrodes.tsv"):
        write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
        coordsystem_fname = _find_matching_sidecar(bids_basename,
                                                   bids_root,
                                                   suffix='coordsystem.json',
                                                   allow_fail=True)
        electrodes_fname = _find_matching_sidecar(bids_basename,
                                                  bids_root,
                                                  suffix="electrodes.tsv",
                                                  allow_fail=True)
        assert coordsystem_fname is None
        assert electrodes_fname is None

    # create montage in head frame and set should result in
    # warning if landmarks not set
    montage = mne.channels.make_dig_montage(ch_pos=ch_pos, coord_frame="head")
    raw.set_montage(montage)
    with pytest.warns(RuntimeWarning,
                      match='Setting montage not possible '
                      'if anatomical landmarks'):
        write_raw_bids(raw, bids_basename, bids_root, overwrite=True)

    montage = mne.channels.make_dig_montage(ch_pos=ch_pos,
                                            coord_frame="head",
                                            nasion=[1, 0, 0],
                                            lpa=[0, 1, 0],
                                            rpa=[0, 0, 1])
    raw.set_montage(montage)
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)

    # obtain the sensor positions and assert ch_coords are same
    raw_test = read_raw_bids(bids_basename, bids_root, verbose=True)
    assert not object_diff(raw.info['chs'], raw_test.info['chs'])

    # modify coordinate frame to not-captrak
    coordsystem_fname = _find_matching_sidecar(bids_basename,
                                               bids_root,
                                               suffix='coordsystem.json',
                                               allow_fail=True)
    _update_sidecar(coordsystem_fname, 'EEGCoordinateSystem', 'besa')
    with pytest.warns(RuntimeWarning,
                      match='EEG Coordinate frame is not '
                      'accepted BIDS keyword'):
        raw_test = read_raw_bids(bids_basename, bids_root)
        assert raw_test.info['dig'] is None