Esempio n. 1
0
def test_handle_channel_type_casing(tmpdir):
    """Test that non-uppercase entries in the `type` column are accepted."""
    bids_path = _bids_path.copy().update(root=tmpdir)
    raw = _read_raw_fif(raw_fname, verbose=False)

    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    ch_path = bids_path.copy().update(root=tmpdir,
                                      datatype='meg',
                                      suffix='channels',
                                      extension='.tsv')
    bids_channels_fname = ch_path.fpath

    # Convert all channel type entries to lowercase.
    channels_data = _from_tsv(bids_channels_fname)
    channels_data['type'] = [t.lower() for t in channels_data['type']]
    _to_tsv(channels_data, bids_channels_fname)

    with pytest.warns(RuntimeWarning, match='lowercase spelling'):
        read_raw_bids(bids_path)
Esempio n. 2
0
def test_read_participants_handedness_and_sex_mapping(hand_bids, hand_mne,
                                                      sex_bids, sex_mne):
    """Test we're correctly mapping handedness and sex between BIDS and MNE."""
    bids_root = _TempDir()
    bids_path = _bids_path.copy().update(root=bids_root, datatype='meg')
    participants_tsv_fpath = op.join(bids_root, 'participants.tsv')
    raw = _read_raw_fif(raw_fname, verbose=False)

    # Avoid that we end up with subject information stored in the raw data.
    raw.info['subject_info'] = {}
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    participants_tsv = _from_tsv(participants_tsv_fpath)
    participants_tsv['hand'][0] = hand_bids
    participants_tsv['sex'][0] = sex_bids
    _to_tsv(participants_tsv, participants_tsv_fpath)

    raw = read_raw_bids(bids_path=bids_path)
    assert raw.info['subject_info']['hand'] is hand_mne
    assert raw.info['subject_info']['sex'] is sex_mne
Esempio n. 3
0
def test_bads_reading():
    bids_root = _TempDir()
    bids_path = _bids_path.copy().update(root=bids_root, datatype='meg')
    bads_raw = ['MEG 0112', 'MEG 0113']
    bads_sidecar = ['EEG 053', 'MEG 2443']

    # Produce conflicting information between raw and sidecar file.
    raw = _read_raw_fif(raw_fname, verbose=False)
    raw.info['bads'] = bads_sidecar
    write_raw_bids(raw, bids_path, verbose=False)

    raw = _read_raw(bids_path.copy().update(extension='.fif').fpath,
                    preload=True)
    raw.info['bads'] = bads_raw
    raw.save(raw.filenames[0], overwrite=True)

    # Upon reading the data, only the sidecar info should be present.
    raw = read_raw_bids(bids_path=bids_path, verbose=False)
    assert len(raw.info['bads']) == len(bads_sidecar)
    assert set(raw.info['bads']) == set(bads_sidecar)
Esempio n. 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)
Esempio n. 5
0
def test_keep_essential_annotations(tmpdir):
    """Test that essential Annotations are not omitted during I/O roundtrip."""
    raw = _read_raw_fif(raw_fname)
    annotations = mne.Annotations(onset=[raw.times[0]],
                                  duration=[1],
                                  description=['BAD_ACQ_SKIP'])
    raw.set_annotations(annotations)

    # Write data, remove events.tsv, then try to read again
    bids_path = BIDSPath(subject='01',
                         task='task',
                         datatype='meg',
                         root=tmpdir)
    with pytest.warns(RuntimeWarning, match='Acquisition skips detected'):
        write_raw_bids(raw, bids_path, overwrite=True)

    bids_path.copy().update(suffix='events', extension='.tsv').fpath.unlink()
    raw_read = read_raw_bids(bids_path)

    assert len(raw_read.annotations) == len(raw.annotations) == 1
    assert (raw_read.annotations[0]['description'] == raw.annotations[0]
            ['description'])
Esempio n. 6
0
def test_get_head_mri_trans_ctf(fname, tmpdir):
    """Test getting a trans object from BIDS data in CTF."""
    import nibabel as nib

    ctf_data_path = op.join(testing.data_path(), 'CTF')
    raw_ctf_fname = op.join(ctf_data_path, fname)
    raw_ctf = _read_raw_ctf(raw_ctf_fname, clean_names=True)
    bids_path = _bids_path.copy().update(root=tmpdir)
    write_raw_bids(raw_ctf, bids_path, overwrite=False)

    # Take a fake trans
    trans = mne.read_trans(raw_fname.replace('_raw.fif', '-trans.fif'))

    # Get the T1 weighted MRI data file ... test write_anat with a nibabel
    # image instead of a file path
    t1w_mgh = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
    t1w_mgh = nib.load(t1w_mgh)

    t1w_bids_path = BIDSPath(subject=subject_id,
                             session=session_id,
                             acquisition=acq,
                             root=tmpdir)
    landmarks = get_anat_landmarks(t1w_mgh,
                                   raw_ctf.info,
                                   trans,
                                   fs_subject='sample',
                                   fs_subjects_dir=op.join(
                                       data_path, 'subjects'))
    write_anat(t1w_mgh, bids_path=t1w_bids_path, landmarks=landmarks)

    # Try to get trans back through fitting points
    estimated_trans = get_head_mri_trans(bids_path=bids_path,
                                         extra_params=dict(clean_names=True),
                                         fs_subject='sample',
                                         fs_subjects_dir=op.join(
                                             data_path, 'subjects'))

    assert_almost_equal(trans['trans'], estimated_trans['trans'])
Esempio n. 7
0
def test_report(tmpdir):
    """Test that report generated works as intended."""
    bids_root = str(tmpdir)
    raw = mne.io.read_raw_fif(raw_fname, verbose=False)
    raw.info['line_freq'] = 60
    bids_path.update(root=bids_root)
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    report = make_report(bids_root)

    expected_report = \
    f"""This dataset was created by [Unspecified] and conforms to BIDS version {BIDS_VERSION}.
This report was generated with MNE-BIDS (https://doi.org/10.21105/joss.01896).
The dataset consists of 1 participants (sex were all unknown; handedness were
all unknown; ages all unknown) and 1 recording sessions: 01. Data was recorded
using a MEG system (Elekta manufacturer) sampled at 300.31 Hz with line noise at
60.0 Hz. The following software filters were applied during recording:
SpatialCompensation. There was 1 scan in total. Recording durations ranged from
20.0 to 20.0 seconds (mean = 20.0, std = 0.0), for a total of 20.0 seconds of
data recorded over all scans. For each dataset, there were on average 376.0 (std
= 0.0) recording channels per scan, out of which 374.0 (std = 0.0) were used in
analysis (2.0 +/- 0.0 were removed from analysis)."""  # noqa

    assert report == expected_report
Esempio n. 8
0
def test_report():
    """Test that report generated works as intended."""
    bids_root = _TempDir()
    raw = mne.io.read_raw_fif(raw_fname, verbose=False)
    raw.info['line_freq'] = 60
    bids_path.update(root=bids_root)
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    report = make_report(bids_root)
    print(report)

    expected_report = \
    """This dataset was created with BIDS version 1.4.0 by Please cite MNE-BIDS in your
publication before removing this (citations in README). This report was
generated with MNE-BIDS (https://doi.org/10.21105/joss.01896). The dataset
consists of 1 participants (sex were all unknown; handedness were all unknown;
ages all unknown)and 1 recording sessions: 01. Data was recorded using a MEG
system (Elekta manufacturer) sampled at 300.31 Hz with line noise at 60 Hz.
There was 1 scan in total. Recording durations ranged from 20.0 to 20.0 seconds
(mean = 20.0, std = 0.0), for a total of 20.0 seconds of data recorded over all
scans. For each dataset, there were on average 376.0 (std = 0.0) recording
channels per scan, out of which 374.0 (std = 0.0) were used in analysis (2.0 +/-
0.0 were removed from analysis)."""  # noqa
    assert report == expected_report
Esempio n. 9
0
def test_get_matched_emptyroom_ties():
    """Test that we receive a warning on a date tie."""
    bids_root = _TempDir()
    session = '20010101'
    er_dir = make_bids_folders(subject='emptyroom',
                               session=session,
                               kind='meg',
                               bids_root=bids_root)

    meas_date = (datetime.strptime(session,
                                   '%Y%m%d').replace(tzinfo=timezone.utc))

    raw = mne.io.read_raw_fif(raw_fname)
    er_raw_fname = op.join(data_path, 'MEG', 'sample', 'ernoise_raw.fif')
    raw.copy().crop(0, 10).save(er_raw_fname, overwrite=True)
    er_raw = mne.io.read_raw_fif(er_raw_fname)

    if check_version('mne', '0.20'):
        raw.set_meas_date(meas_date)
        er_raw.set_meas_date(meas_date)
    else:
        raw.info['meas_date'] = (meas_date.timestamp(), 0)
        er_raw.info['meas_date'] = (meas_date.timestamp(), 0)

    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    er_bids_path = BIDSPath(subject='emptyroom', session=session)
    er_basename_1 = str(er_bids_path)
    er_basename_2 = make_bids_basename(subject='emptyroom',
                                       session=session,
                                       task='noise')
    er_raw.save(op.join(er_dir, f'{er_basename_1}_meg.fif'))
    er_raw.save(op.join(er_dir, f'{er_basename_2}_meg.fif'))

    with pytest.warns(RuntimeWarning, match='Found more than one'):
        get_matched_empty_room(bids_basename=bids_basename,
                               bids_root=bids_root)
Esempio n. 10
0
def test_read_raw_kind():
    """Test that read_raw_bids() can infer the kind if need be."""
    bids_root = _TempDir()
    raw = mne.io.read_raw_fif(raw_fname, verbose=False)
    write_raw_bids(raw,
                   bids_basename,
                   bids_root,
                   overwrite=True,
                   verbose=False)

    raw_1 = read_raw_bids(bids_basename=bids_basename,
                          bids_root=bids_root,
                          kind='meg')
    raw_2 = read_raw_bids(bids_basename=bids_basename,
                          bids_root=bids_root,
                          kind=None)
    raw_3 = read_raw_bids(bids_basename=bids_basename, bids_root=bids_root)

    raw_1.crop(0, 2).load_data()
    raw_2.crop(0, 2).load_data()
    raw_3.crop(0, 2).load_data()

    assert raw_1 == raw_2
    assert raw_1 == raw_3
Esempio n. 11
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
Esempio n. 12
0
def test_handle_scans_reading():
    """Test reading data from a BIDS scans.tsv file."""
    bids_root = _TempDir()
    raw = _read_raw_fif(raw_fname)
    suffix = "meg"

    # write copy of raw with line freq of 60
    # bids basename and fname
    bids_path = BIDSPath(subject='01',
                         session='01',
                         task='audiovisual',
                         run='01',
                         datatype=suffix,
                         root=bids_root)
    bids_path = write_raw_bids(raw, bids_path, overwrite=True)
    raw_01 = read_raw_bids(bids_path)

    # find sidecar scans.tsv file and alter the
    # acquisition time to not have the optional microseconds
    scans_path = BIDSPath(subject=bids_path.subject,
                          session=bids_path.session,
                          root=bids_root,
                          suffix='scans',
                          extension='.tsv')
    scans_tsv = _from_tsv(scans_path)
    acq_time_str = scans_tsv['acq_time'][0]
    acq_time = datetime.strptime(acq_time_str, '%Y-%m-%dT%H:%M:%S.%fZ')
    acq_time = acq_time.replace(tzinfo=timezone.utc)
    new_acq_time = acq_time_str.split('.')[0]
    assert acq_time == raw_01.info['meas_date']
    scans_tsv['acq_time'][0] = new_acq_time
    _to_tsv(scans_tsv, scans_path)

    # now re-load the data and it should be different
    # from the original date and the same as the newly altered date
    raw_02 = read_raw_bids(bids_path)
    new_acq_time += '.0Z'
    new_acq_time = datetime.strptime(new_acq_time, '%Y-%m-%dT%H:%M:%S.%fZ')
    new_acq_time = new_acq_time.replace(tzinfo=timezone.utc)
    assert raw_02.info['meas_date'] == new_acq_time
    assert new_acq_time != raw_01.info['meas_date']
Esempio n. 13
0
def test_handle_chpi_reading(tmpdir):
    """Test reading of cHPI information."""
    raw = _read_raw_fif(raw_fname_chpi, allow_maxshield=True)
    root = tmpdir.mkdir('chpi')
    bids_path = BIDSPath(subject='01',
                         session='01',
                         task='audiovisual',
                         run='01',
                         root=root,
                         datatype='meg')
    bids_path = write_raw_bids(raw, bids_path)

    raw_read = read_raw_bids(bids_path)
    assert raw_read.info['hpi_subsystem'] is not None

    # cause conflicts between cHPI info in sidecar and raw data
    meg_json_path = bids_path.copy().update(suffix='meg', extension='.json')
    with open(meg_json_path, 'r', encoding='utf-8') as f:
        meg_json_data = json.load(f)

    # cHPI frequency mismatch
    meg_json_data_freq_mismatch = meg_json_data.copy()
    meg_json_data_freq_mismatch['HeadCoilFrequency'][0] = 123
    with open(meg_json_path, 'w', encoding='utf-8') as f:
        json.dump(meg_json_data_freq_mismatch, f)

    with pytest.raises(ValueError, match='cHPI coil frequencies'):
        raw_read = read_raw_bids(bids_path)

    # cHPI "off" according to sidecar, but present in the data
    meg_json_data_chpi_mismatch = meg_json_data.copy()
    meg_json_data_chpi_mismatch['ContinuousHeadLocalization'] = False
    with open(meg_json_path, 'w', encoding='utf-8') as f:
        json.dump(meg_json_data_chpi_mismatch, f)

    raw_read = read_raw_bids(bids_path)
    assert raw_read.info['hpi_subsystem'] is None
    assert raw_read.info['hpi_meas'] == []
Esempio n. 14
0
def test_handle_info_reading(tmpdir):
    """Test reading information from a BIDS sidecar.json file."""
    # 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=tmpdir)
    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

    # setting line_freq to None should produce 'n/a' in the JSON sidecar
    raw.info['line_freq'] = None
    write_raw_bids(raw, bids_path, overwrite=True)
    raw = read_raw_bids(bids_path=bids_path)
    assert raw.info['line_freq'] is None

    with open(sidecar_fname, 'r', encoding='utf-8') as fin:
        sidecar_json = json.load(fin)
    assert sidecar_json["PowerLineFrequency"] == 'n/a'

    # 2. if line frequency is not set in raw file, then ValueError
    del raw.info['line_freq']
    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`
    raw.info['line_freq'] = 60
    write_raw_bids(raw, bids_path, overwrite=True)
    deriv_dir = tmpdir.mkdir("derivatives")
    sidecar_copy = deriv_dir / op.basename(sidecar_fname)
    with open(sidecar_fname, "r", encoding='utf-8') 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
Esempio n. 15
0
def test_get_head_mri_trans(tmpdir):
    """Test getting a trans object from BIDS data."""
    import nibabel as nib

    event_id = {
        'Auditory/Left': 1,
        'Auditory/Right': 2,
        'Visual/Left': 3,
        'Visual/Right': 4,
        'Smiley': 5,
        'Button': 32
    }
    events_fname = op.join(data_path, 'MEG', 'sample',
                           'sample_audvis_trunc_raw-eve.fif')
    subjects_dir = op.join(data_path, 'subjects')

    # Drop unknown events.
    events = mne.read_events(events_fname)
    events = events[events[:, 2] != 0]

    # Write it to BIDS
    raw = _read_raw_fif(raw_fname)
    bids_path = _bids_path.copy().update(root=tmpdir)
    write_raw_bids(raw,
                   bids_path,
                   events_data=events,
                   event_id=event_id,
                   overwrite=False)

    # We cannot recover trans if no MRI has yet been written
    with pytest.raises(RuntimeError, match='Did not find any T1w'):
        estimated_trans = get_head_mri_trans(bids_path=bids_path,
                                             fs_subject='sample',
                                             fs_subjects_dir=subjects_dir)

    # Write some MRI data and supply a `trans` so that a sidecar gets written
    trans = mne.read_trans(raw_fname.replace('_raw.fif', '-trans.fif'))

    # Get the T1 weighted MRI data file ... test write_anat with a nibabel
    # image instead of a file path
    t1w_mgh = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
    t1w_mgh = nib.load(t1w_mgh)

    landmarks = get_anat_landmarks(t1w_mgh,
                                   raw.info,
                                   trans,
                                   fs_subject='sample',
                                   fs_subjects_dir=subjects_dir)
    t1w_bids_path = write_anat(t1w_mgh,
                               bids_path=bids_path,
                               landmarks=landmarks,
                               verbose=True)
    anat_dir = bids_path.directory

    # Try to get trans back through fitting points
    estimated_trans = get_head_mri_trans(bids_path=bids_path,
                                         fs_subject='sample',
                                         fs_subjects_dir=subjects_dir)

    assert trans['from'] == estimated_trans['from']
    assert trans['to'] == estimated_trans['to']
    assert_almost_equal(trans['trans'], estimated_trans['trans'])

    # provoke an error by introducing NaNs into MEG coords
    raw.info['dig'][0]['r'] = np.full(3, np.nan)
    sh.rmtree(anat_dir)
    bad_landmarks = get_anat_landmarks(t1w_mgh, raw.info, trans, 'sample',
                                       op.join(data_path, 'subjects'))
    write_anat(t1w_mgh, bids_path=t1w_bids_path, landmarks=bad_landmarks)
    with pytest.raises(RuntimeError, match='AnatomicalLandmarkCoordinates'):
        estimated_trans = get_head_mri_trans(bids_path=t1w_bids_path,
                                             fs_subject='sample',
                                             fs_subjects_dir=subjects_dir)

    # test we are permissive for different casings of landmark names in the
    # sidecar, and also accept "nasion" instead of just "NAS"
    raw = _read_raw_fif(raw_fname)
    write_raw_bids(raw,
                   bids_path,
                   events_data=events,
                   event_id=event_id,
                   overwrite=True)  # overwrite with new acq
    t1w_bids_path = write_anat(t1w_mgh,
                               bids_path=bids_path,
                               landmarks=landmarks,
                               overwrite=True)

    t1w_json_fpath = t1w_bids_path.copy().update(extension='.json').fpath
    with t1w_json_fpath.open('r', encoding='utf-8') as f:
        t1w_json = json.load(f)

    coords = t1w_json['AnatomicalLandmarkCoordinates']
    coords['lpa'] = coords['LPA']
    coords['Rpa'] = coords['RPA']
    coords['Nasion'] = coords['NAS']
    del coords['LPA'], coords['RPA'], coords['NAS']

    _write_json(t1w_json_fpath, t1w_json, overwrite=True)

    estimated_trans = get_head_mri_trans(bids_path=bids_path,
                                         fs_subject='sample',
                                         fs_subjects_dir=subjects_dir)
    assert_almost_equal(trans['trans'], estimated_trans['trans'])

    # Test t1_bids_path parameter
    #
    # Case 1: different BIDS roots
    meg_bids_path = _bids_path.copy().update(root=tmpdir / 'meg_root')
    t1_bids_path = _bids_path.copy().update(root=tmpdir / 'mri_root')
    raw = _read_raw_fif(raw_fname)

    write_raw_bids(raw, bids_path=meg_bids_path)
    landmarks = get_anat_landmarks(t1w_mgh,
                                   raw.info,
                                   trans,
                                   fs_subject='sample',
                                   fs_subjects_dir=subjects_dir)
    write_anat(t1w_mgh, bids_path=t1_bids_path, landmarks=landmarks)
    read_trans = get_head_mri_trans(bids_path=meg_bids_path,
                                    t1_bids_path=t1_bids_path,
                                    fs_subject='sample',
                                    fs_subjects_dir=subjects_dir)
    assert np.allclose(trans['trans'], read_trans['trans'])

    # Case 2: different sessions
    raw = _read_raw_fif(raw_fname)
    meg_bids_path = _bids_path.copy().update(root=tmpdir / 'session_test',
                                             session='01')
    t1_bids_path = meg_bids_path.copy().update(session='02')

    write_raw_bids(raw, bids_path=meg_bids_path)
    write_anat(t1w_mgh, bids_path=t1_bids_path, landmarks=landmarks)
    read_trans = get_head_mri_trans(bids_path=meg_bids_path,
                                    t1_bids_path=t1_bids_path,
                                    fs_subject='sample',
                                    fs_subjects_dir=subjects_dir)
    assert np.allclose(trans['trans'], read_trans['trans'])

    # Test that incorrect subject directory throws error
    with pytest.raises(ValueError, match='Could not find'):
        estimated_trans = get_head_mri_trans(bids_path=bids_path,
                                             fs_subject='bad',
                                             fs_subjects_dir=subjects_dir)
Esempio n. 16
0
def test_get_matched_empty_room():
    """Test reading of empty room data."""
    bids_root = _TempDir()

    raw = mne.io.read_raw_fif(raw_fname)
    bids_basename = make_bids_basename(subject='01',
                                       session='01',
                                       task='audiovisual',
                                       run='01')
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)

    er_basename = get_matched_empty_room(bids_basename=bids_basename,
                                         bids_root=bids_root)
    assert er_basename is None

    # testing data has no noise recording, so save the actual data
    # as if it were noise
    er_raw_fname = op.join(data_path, 'MEG', 'sample', 'ernoise_raw.fif')
    raw.crop(0, 10).save(er_raw_fname, overwrite=True)

    er_raw = mne.io.read_raw_fif(er_raw_fname)
    er_date = er_raw.info['meas_date']
    if not isinstance(er_date, datetime):
        # mne < v0.20
        er_date = datetime.fromtimestamp(er_raw.info['meas_date'][0])
    er_date = er_date.strftime('%Y%m%d')
    er_bids_basename = make_bids_basename(subject='emptyroom',
                                          task='noise',
                                          session=er_date)
    write_raw_bids(er_raw, er_bids_basename, bids_root, overwrite=True)

    recovered_er_basename = get_matched_empty_room(bids_basename=bids_basename,
                                                   bids_root=bids_root)
    assert er_bids_basename == recovered_er_basename

    # assert that we get best emptyroom if there are multiple available
    sh.rmtree(op.join(bids_root, 'sub-emptyroom'))
    dates = ['20021204', '20021201', '20021001']
    for date in dates:
        er_bids_basename.update(session=date)
        er_meas_date = datetime.strptime(date, '%Y%m%d')
        er_meas_date = er_meas_date.replace(tzinfo=timezone.utc)

        if check_version('mne', '0.20'):
            er_raw.set_meas_date(er_meas_date)
        else:
            er_raw.info['meas_date'] = (er_meas_date.timestamp(), 0)
        write_raw_bids(er_raw, er_bids_basename, bids_root)

    best_er_basename = get_matched_empty_room(bids_basename=bids_basename,
                                              bids_root=bids_root)
    assert '20021204' in best_er_basename

    # assert that we get error if meas_date is not available.
    raw = read_raw_bids(bids_basename=bids_basename,
                        bids_root=bids_root,
                        kind='meg')
    if check_version('mne', '0.20'):
        raw.set_meas_date(None)
    else:
        raw.info['meas_date'] = None
        raw.annotations.orig_time = None
    anonymize_info(raw.info)
    write_raw_bids(raw, bids_basename, bids_root, overwrite=True)
    with pytest.raises(ValueError,
                       match='The provided recording does not '
                       'have a measurement date set'):
        get_matched_empty_room(bids_basename=bids_basename,
                               bids_root=bids_root)
Esempio n. 17
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']
Esempio n. 18
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
Esempio n. 19
0
def test_write_read_fif_split_file(tmp_path, monkeypatch):
    """Test split files are read correctly."""
    # load raw test file, extend it to be larger than 2gb, and save it
    bids_root = tmp_path / 'bids'
    tmp_dir = tmp_path / 'tmp'
    tmp_dir.mkdir()

    bids_path = _bids_path.copy().update(root=bids_root, datatype='meg')
    raw = _read_raw_fif(raw_fname, verbose=False)
    bids_path.update(acquisition=None)
    write_raw_bids(raw, bids_path, verbose=False)
    bids_path.update(acquisition='01')
    n_channels = len(raw.ch_names)
    n_times = int(2.5e6 / n_channels)  # enough to produce a 10MB split
    data = np.empty((n_channels, n_times), dtype=np.float32)
    raw = mne.io.RawArray(data, raw.info)
    big_fif_fname = pathlib.Path(tmp_dir) / 'test_raw.fif'

    split_size = '10MB'
    raw.save(big_fif_fname, split_size=split_size)
    raw = _read_raw_fif(big_fif_fname, verbose=False)

    with monkeypatch.context() as m:  # Force MNE-BIDS to split at 10MB
        m.setattr(mne_bids.write, '_FIFF_SPLIT_SIZE', split_size)
        write_raw_bids(raw, bids_path, verbose=False)

    # test whether split raw files were read correctly
    raw1 = read_raw_bids(bids_path=bids_path)
    assert 'split-01' in str(bids_path.fpath)
    bids_path.update(split='01')
    raw2 = read_raw_bids(bids_path=bids_path)
    bids_path.update(split='02')
    raw3 = read_raw_bids(bids_path=bids_path)
    assert len(raw) == len(raw1)
    assert len(raw) == len(raw2)
    assert len(raw) > len(raw3)

    # check that split files both appear in scans.tsv
    scans_tsv = BIDSPath(
        subject=subject_id, session=session_id,
        suffix='scans', extension='.tsv',
        root=bids_root)
    scan_data = _from_tsv(scans_tsv)
    scan_fnames = scan_data['filename']
    scan_acqtime = scan_data['acq_time']

    assert len(scan_fnames) == 3
    assert 'split-01' in scan_fnames[0] and 'split-02' in scan_fnames[1]
    # check that the acq_times in scans.tsv are the same
    assert scan_acqtime[0] == scan_acqtime[1]
    # check the recordings are in the correct order
    assert raw2.first_time < raw3.first_time

    # check whether non-matching acq_times are caught
    scan_data['acq_time'][0] = scan_acqtime[0].split('.')[0]
    _to_tsv(scan_data, scans_tsv)
    with pytest.raises(ValueError,
                       match='Split files must have the same acq_time.'):
        read_raw_bids(bids_path)

    # reset scans.tsv file for downstream tests
    scan_data['acq_time'][0] = scan_data['acq_time'][1]
    _to_tsv(scan_data, scans_tsv)
Esempio n. 20
0
def test_get_head_mri_trans():
    """Test getting a trans object from BIDS data."""
    import nibabel as nib

    event_id = {
        'Auditory/Left': 1,
        'Auditory/Right': 2,
        'Visual/Left': 3,
        'Visual/Right': 4,
        'Smiley': 5,
        'Button': 32
    }
    events_fname = op.join(data_path, 'MEG', 'sample',
                           'sample_audvis_trunc_raw-eve.fif')

    # Write it to BIDS
    raw = mne.io.read_raw_fif(raw_fname)
    bids_root = _TempDir()
    with pytest.warns(RuntimeWarning, match='No line frequency'):
        write_raw_bids(raw,
                       bids_basename,
                       bids_root,
                       events_data=events_fname,
                       event_id=event_id,
                       overwrite=False)

    # We cannot recover trans, if no MRI has yet been written
    with pytest.raises(RuntimeError):
        estimated_trans = get_head_mri_trans(bids_basename=bids_basename,
                                             bids_root=bids_root)

    # Write some MRI data and supply a `trans` so that a sidecar gets written
    trans = mne.read_trans(raw_fname.replace('_raw.fif', '-trans.fif'))

    # Get the T1 weighted MRI data file ... test write_anat with a nibabel
    # image instead of a file path
    t1w_mgh = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
    t1w_mgh = nib.load(t1w_mgh)

    anat_dir = write_anat(bids_root,
                          subject_id,
                          t1w_mgh,
                          session_id,
                          acq,
                          raw=raw,
                          trans=trans,
                          verbose=True)

    # Try to get trans back through fitting points
    estimated_trans = get_head_mri_trans(bids_basename=bids_basename,
                                         bids_root=bids_root)

    assert trans['from'] == estimated_trans['from']
    assert trans['to'] == estimated_trans['to']
    assert_almost_equal(trans['trans'], estimated_trans['trans'])
    print(trans)
    print(estimated_trans)

    # provoke an error by introducing NaNs into MEG coords
    with pytest.raises(RuntimeError, match='AnatomicalLandmarkCoordinates'):
        raw.info['dig'][0]['r'] = np.ones(3) * np.nan
        sh.rmtree(anat_dir)
        write_anat(bids_root,
                   subject_id,
                   t1w_mgh,
                   session_id,
                   acq,
                   raw=raw,
                   trans=trans,
                   verbose=True)
        estimated_trans = get_head_mri_trans(bids_basename=bids_basename,
                                             bids_root=bids_root)
Esempio n. 21
0
def test_get_head_mri_trans(tmp_path):
    """Test getting a trans object from BIDS data."""
    import nibabel as nib

    event_id = {'Auditory/Left': 1, 'Auditory/Right': 2, 'Visual/Left': 3,
                'Visual/Right': 4, 'Smiley': 5, 'Button': 32}
    events_fname = op.join(data_path, 'MEG', 'sample',
                           'sample_audvis_trunc_raw-eve.fif')
    subjects_dir = op.join(data_path, 'subjects')

    # Drop unknown events.
    events = mne.read_events(events_fname)
    events = events[events[:, 2] != 0]

    # Write it to BIDS
    raw = _read_raw_fif(raw_fname)
    bids_path = _bids_path.copy().update(
        root=tmp_path, datatype='meg', suffix='meg'
    )
    write_raw_bids(raw, bids_path, events_data=events, event_id=event_id,
                   overwrite=False)

    # We cannot recover trans if no MRI has yet been written
    with pytest.raises(FileNotFoundError, match='Did not find'):
        estimated_trans = get_head_mri_trans(
            bids_path=bids_path, fs_subject='sample',
            fs_subjects_dir=subjects_dir)

    # Write some MRI data and supply a `trans` so that a sidecar gets written
    trans = mne.read_trans(raw_fname.replace('_raw.fif', '-trans.fif'))

    # Get the T1 weighted MRI data file ... test write_anat with a nibabel
    # image instead of a file path
    t1w_mgh = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
    t1w_mgh = nib.load(t1w_mgh)

    landmarks = get_anat_landmarks(
        t1w_mgh, raw.info, trans, fs_subject='sample',
        fs_subjects_dir=subjects_dir)
    t1w_bids_path = bids_path.copy().update(
        datatype='anat', suffix='T1w'
    )
    t1w_bids_path = write_anat(
        t1w_mgh, bids_path=t1w_bids_path, landmarks=landmarks, verbose=True
    )
    anat_dir = t1w_bids_path.directory

    # Try to get trans back through fitting points
    estimated_trans = get_head_mri_trans(
        bids_path=bids_path, fs_subject='sample', fs_subjects_dir=subjects_dir)

    assert trans['from'] == estimated_trans['from']
    assert trans['to'] == estimated_trans['to']
    assert_almost_equal(trans['trans'], estimated_trans['trans'])

    # provoke an error by introducing NaNs into MEG coords
    raw.info['dig'][0]['r'] = np.full(3, np.nan)
    sh.rmtree(anat_dir)
    bad_landmarks = get_anat_landmarks(t1w_mgh, raw.info, trans, 'sample',
                                       op.join(data_path, 'subjects'))
    write_anat(t1w_mgh, bids_path=t1w_bids_path, landmarks=bad_landmarks)
    with pytest.raises(RuntimeError, match='AnatomicalLandmarkCoordinates'):
        estimated_trans = get_head_mri_trans(bids_path=t1w_bids_path,
                                             fs_subject='sample',
                                             fs_subjects_dir=subjects_dir)

    # test raw with no fiducials to provoke error
    t1w_bids_path = write_anat(  # put back
        t1w_mgh, bids_path=t1w_bids_path, landmarks=landmarks, overwrite=True
    )
    montage = raw.get_montage()
    montage.remove_fiducials()
    raw_test = raw.copy()
    raw_test.set_montage(montage)
    raw_test.save(bids_path.fpath, overwrite=True)

    with pytest.raises(RuntimeError, match='Could not extract fiducial'):
        get_head_mri_trans(bids_path=bids_path, fs_subject='sample',
                           fs_subjects_dir=subjects_dir)

    # test we are permissive for different casings of landmark names in the
    # sidecar, and also accept "nasion" instead of just "NAS"
    raw = _read_raw_fif(raw_fname)
    write_raw_bids(raw, bids_path, events_data=events, event_id=event_id,
                   overwrite=True)  # overwrite with new acq
    t1w_bids_path = write_anat(
        t1w_mgh, bids_path=t1w_bids_path, landmarks=landmarks, overwrite=True
    )

    t1w_json_fpath = t1w_bids_path.copy().update(extension='.json').fpath
    with t1w_json_fpath.open('r', encoding='utf-8') as f:
        t1w_json = json.load(f)

    coords = t1w_json['AnatomicalLandmarkCoordinates']
    coords['lpa'] = coords['LPA']
    coords['Rpa'] = coords['RPA']
    coords['Nasion'] = coords['NAS']
    del coords['LPA'], coords['RPA'], coords['NAS']

    _write_json(t1w_json_fpath, t1w_json, overwrite=True)

    estimated_trans = get_head_mri_trans(
        bids_path=bids_path,
        fs_subject='sample', fs_subjects_dir=subjects_dir)
    assert_almost_equal(trans['trans'], estimated_trans['trans'])

    # Test t1_bids_path parameter
    #
    # Case 1: different BIDS roots
    meg_bids_path = _bids_path.copy().update(
        root=tmp_path / 'meg_root', datatype='meg', suffix='meg'
    )
    t1_bids_path = _bids_path.copy().update(
        root=tmp_path / 'mri_root', task=None, run=None
    )
    raw = _read_raw_fif(raw_fname)

    write_raw_bids(raw, bids_path=meg_bids_path)
    landmarks = get_anat_landmarks(
        t1w_mgh, raw.info, trans, fs_subject='sample',
        fs_subjects_dir=subjects_dir)
    write_anat(t1w_mgh, bids_path=t1_bids_path, landmarks=landmarks)
    read_trans = get_head_mri_trans(
        bids_path=meg_bids_path, t1_bids_path=t1_bids_path,
        fs_subject='sample', fs_subjects_dir=subjects_dir)
    assert np.allclose(trans['trans'], read_trans['trans'])

    # Case 2: different sessions
    raw = _read_raw_fif(raw_fname)
    meg_bids_path = _bids_path.copy().update(
        root=tmp_path / 'session_test', session='01', datatype='meg',
        suffix='meg'
    )
    t1_bids_path = meg_bids_path.copy().update(
        session='02', task=None, run=None, datatype='anat', suffix='T1w'
    )

    write_raw_bids(raw, bids_path=meg_bids_path)
    write_anat(t1w_mgh, bids_path=t1_bids_path, landmarks=landmarks)
    read_trans = get_head_mri_trans(
        bids_path=meg_bids_path, t1_bids_path=t1_bids_path,
        fs_subject='sample', fs_subjects_dir=subjects_dir)
    assert np.allclose(trans['trans'], read_trans['trans'])

    # Test that incorrect subject directory throws error
    with pytest.raises(ValueError, match='Could not find'):
        estimated_trans = get_head_mri_trans(
            bids_path=bids_path, fs_subject='bad',
            fs_subjects_dir=subjects_dir)

    # Case 3: write with suffix for kind
    landmarks2 = landmarks.copy()
    landmarks2.dig[0]['r'] *= -1
    landmarks2.save(tmp_path / 'landmarks2.fif')
    landmarks2 = tmp_path / 'landmarks2.fif'
    write_anat(t1w_mgh, bids_path=t1_bids_path, overwrite=True,
               deface=True,
               landmarks={"coreg": landmarks, "deface": landmarks2})
    read_trans1 = get_head_mri_trans(
        bids_path=meg_bids_path, t1_bids_path=t1_bids_path,
        fs_subject='sample', fs_subjects_dir=subjects_dir,
        kind="coreg")
    assert np.allclose(trans['trans'], read_trans1['trans'])
    read_trans2 = get_head_mri_trans(
        bids_path=meg_bids_path, t1_bids_path=t1_bids_path,
        fs_subject='sample', fs_subjects_dir=subjects_dir,
        kind="deface")
    assert not np.allclose(trans['trans'], read_trans2['trans'])

    # Test we're respecting existing suffix & data type
    # The following path is supposed to mimic a derivative generated by the
    # MNE-BIDS-Pipeline.
    #
    # XXX We MAY want to revise this once the BIDS-Pipeline produces more
    # BIDS-compatible output, e.g. including `channels.tsv` files for written
    # Raw data etc.
    raw = _read_raw_fif(raw_fname)
    deriv_root = tmp_path / 'derivatives' / 'mne-bids-pipeline'
    electrophys_path = (
        deriv_root / 'sub-01' / 'eeg' / 'sub-01_task-av_proc-filt_raw.fif'
    )
    electrophys_path.parent.mkdir(parents=True)
    raw.save(electrophys_path)

    electrophys_bids_path = BIDSPath(
        subject='01', task='av', datatype='eeg', processing='filt',
        suffix='raw', extension='.fif', root=deriv_root,
        check=False
    )
    t1_bids_path = _bids_path.copy().update(
        root=tmp_path / 'mri_root', task=None, run=None
    )
    with pytest.warns(RuntimeWarning, match='Did not find any channels.tsv'):
        get_head_mri_trans(
            bids_path=electrophys_bids_path,
            t1_bids_path=t1_bids_path,
            fs_subject='sample',
            fs_subjects_dir=subjects_dir
        )

    # bids_path without datatype is deprecated
    bids_path = electrophys_bids_path.copy().update(datatype=None)
    with pytest.raises(FileNotFoundError):  # defaut location is all wrong!
        with pytest.warns(DeprecationWarning, match='no datatype'):
            get_head_mri_trans(
                bids_path=bids_path,
                t1_bids_path=t1_bids_path,
                fs_subject='sample',
                fs_subjects_dir=subjects_dir
            )

    # bids_path without suffix is deprecated
    bids_path = electrophys_bids_path.copy().update(suffix=None)
    with pytest.raises(FileNotFoundError):  # defaut location is all wrong!
        with pytest.warns(DeprecationWarning, match='no datatype'):
            get_head_mri_trans(
                bids_path=bids_path,
                t1_bids_path=t1_bids_path,
                fs_subject='sample',
                fs_subjects_dir=subjects_dir
            )

    # Should fail for an unsupported coordinate frame
    raw = _read_raw_fif(raw_fname)
    bids_root = tmp_path / 'unsupported_coord_frame'
    bids_path = BIDSPath(
        subject='01', task='av', datatype='meg', suffix='meg',
        extension='.fif', root=bids_root
    )
    t1_bids_path = _bids_path.copy().update(
        root=tmp_path / 'mri_root', task=None, run=None
    )
    write_raw_bids(raw=raw, bids_path=bids_path, verbose=False)
Esempio n. 22
0
def test_read_participants_data():
    """Test reading information from a BIDS sidecar.json file."""
    bids_root = _TempDir()
    raw = mne.io.read_raw_fif(raw_fname, verbose=False)

    # if subject info was set, we don't roundtrip birthday
    # due to possible anonymization in mne-bids
    subject_info = {
        'hand': 1,
        'sex': 2,
    }
    raw.info['subject_info'] = subject_info
    write_raw_bids(raw,
                   bids_basename,
                   bids_root,
                   overwrite=True,
                   verbose=False)
    raw = read_raw_bids(bids_basename=bids_basename,
                        bids_root=bids_root,
                        kind='meg')
    print(raw.info['subject_info'])
    assert raw.info['subject_info']['hand'] == 1
    assert raw.info['subject_info']['sex'] == 2
    assert raw.info['subject_info'].get('birthday', None) is None

    # if modifying participants tsv, then read_raw_bids reflects that
    participants_tsv_fpath = op.join(bids_root, 'participants.tsv')
    participants_tsv = _from_tsv(participants_tsv_fpath)
    participants_tsv['hand'][0] = 'n/a'
    _to_tsv(participants_tsv, participants_tsv_fpath)
    raw = read_raw_bids(bids_basename=bids_basename,
                        bids_root=Path(bids_root),
                        kind='meg')
    assert raw.info['subject_info']['hand'] == 0
    assert raw.info['subject_info']['sex'] == 2
    assert raw.info['subject_info'].get('birthday', None) is None

    # make sure things are read even if the entries don't make sense
    participants_tsv = _from_tsv(participants_tsv_fpath)
    participants_tsv['hand'][0] = 'righty'
    participants_tsv['sex'][0] = 'malesy'
    _to_tsv(participants_tsv, participants_tsv_fpath)
    with pytest.warns(RuntimeWarning, match='Unable to map'):
        raw = read_raw_bids(bids_basename=bids_basename,
                            bids_root=Path(bids_root),
                            kind='meg')
        assert raw.info['subject_info']['hand'] is None
        assert raw.info['subject_info']['sex'] is None

    # make sure to read in if no participants file
    raw = mne.io.read_raw_fif(raw_fname, verbose=False)
    write_raw_bids(raw,
                   bids_basename,
                   bids_root,
                   overwrite=True,
                   verbose=False)
    os.remove(participants_tsv_fpath)
    with pytest.warns(RuntimeWarning, match='Participants file not found'):
        raw = read_raw_bids(bids_basename=bids_basename,
                            bids_root=Path(bids_root),
                            kind='meg')
        assert raw.info['subject_info'] is None
Esempio n. 23
0
def test_bads_reading():
    bids_root = _TempDir()
    bids_path = _bids_path.copy().update(root=bids_root)
    data_path = BIDSPath(subject=subject_id,
                         session=session_id,
                         datatype='meg',
                         root=bids_root).mkdir().directory
    ch_path = (bids_path.copy().update(suffix='channels', extension='.tsv'))
    channels_fname = op.join(data_path, ch_path.basename)

    raw_bids_fname = (bids_path.copy().update(root=bids_root,
                                              datatype='meg',
                                              suffix='meg',
                                              extension='.fif'))
    raw = _read_raw_fif(raw_fname, verbose=False)

    ###########################################################################
    # bads in FIF only, no `status` column in channels.tsv
    bads = ['EEG 053', 'MEG 2443']
    raw.info['bads'] = bads
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    # Delete `status` column
    tsv_data = _from_tsv(channels_fname)
    del tsv_data['status'], tsv_data['status_description']
    _to_tsv(tsv_data, fname=channels_fname)

    raw = read_raw_bids(bids_path=bids_path, verbose=False)
    assert raw.info['bads'] == bads

    ###########################################################################
    # bads in `status` column in channels.tsv, no bads in raw.info['bads']
    bads = ['EEG 053', 'MEG 2443']
    raw.info['bads'] = bads
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    # Remove info['bads'] from the raw file.
    raw = _read_raw_fif(raw_bids_fname, preload=True, verbose=False)
    raw.info['bads'] = []
    raw.save(raw_bids_fname, overwrite=True, verbose=False)

    raw = read_raw_bids(bids_path=bids_path, verbose=False)
    assert type(raw.info['bads']) is list
    assert set(raw.info['bads']) == set(bads)

    ###########################################################################
    # Different bads in `status` column and raw.info['bads']
    bads_bids = ['EEG 053', 'MEG 2443']
    bads_raw = ['MEG 0112', 'MEG 0131']

    raw.info['bads'] = bads_bids
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)

    # Replace info['bads'] in the raw file.
    raw = _read_raw_fif(raw_bids_fname, preload=True, verbose=False)
    raw.info['bads'] = bads_raw
    raw.save(raw_bids_fname, overwrite=True, verbose=False)

    with pytest.warns(RuntimeWarning, match='conflicting information'):
        raw = read_raw_bids(bids_path=bids_path, verbose=False)
    assert type(raw.info['bads']) is list
    assert set(raw.info['bads']) == set(bads_bids)
Esempio n. 24
0
def test_read_raw_bids_pathlike(tmpdir):
    """Test that read_raw_bids() can handle a Path-like bids_root."""
    bids_path = _bids_path.copy().update(root=tmpdir, datatype='meg')
    raw = _read_raw_fif(raw_fname, verbose=False)
    write_raw_bids(raw, bids_path, overwrite=True, verbose=False)
    raw = read_raw_bids(bids_path=bids_path)
Esempio n. 25
0
def test_handle_ieeg_coords_reading(bids_path, tmpdir):
    """Test reading iEEG coordinates from BIDS files."""
    data_path = op.join(testing.data_path(), 'EDF')
    raw_fname = op.join(data_path, 'test_reduced.edf')
    bids_fname = bids_path.copy().update(datatype='ieeg',
                                         suffix='ieeg',
                                         extension='.edf',
                                         root=tmpdir)
    raw = _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 = ['mni_tal']
    for coord_frame in coordinate_frames:
        # XXX: mne-bids doesn't support multiple electrodes.tsv files
        sh.rmtree(tmpdir)
        montage = mne.channels.make_dig_montage(ch_pos=ch_pos,
                                                coord_frame=coord_frame)
        raw.set_montage(montage)
        write_raw_bids(raw, bids_fname, 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_path=bids_fname, 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(tmpdir)
    write_raw_bids(raw, bids_fname, overwrite=True, verbose=False)

    # obtain the sensor positions and assert ch_coords are same
    raw_test = read_raw_bids(bids_path=bids_fname, 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}
    bids_fname.update(root=tmpdir)
    coordsystem_fname = _find_matching_sidecar(bids_fname,
                                               suffix='coordsystem',
                                               extension='.json')
    electrodes_fname = _find_matching_sidecar(bids_fname,
                                              suffix='electrodes',
                                              extension='.tsv')
    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_path=bids_fname, 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_path=bids_fname, 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 = ['Other']
    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="Defaulting coordinate "
                          "frame to unknown"):
            raw_test = read_raw_bids(bids_path=bids_fname, verbose=False)
            assert raw_test.info['dig'] is not None

    # check that standard template identifiers that are unsupported in
    # mne-python coordinate frames, still get read in, but produce a warning
    coordinate_frames = [
        'individual', 'fsnative', 'scanner', 'ICBM452AirSpace', 'NIHPD'
    ]
    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=f"iEEG Coordinate frame {coord_frame} "
                          f"is not a readable BIDS keyword "):
            raw_test = read_raw_bids(bids_path=bids_fname, verbose=False)
            assert raw_test.info['dig'] is not None

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

    # if we delete the coordsystem.json file, an error will be raised
    os.remove(coordsystem_fname)
    with pytest.raises(RuntimeError,
                       match='BIDS mandates that '
                       'the coordsystem.json'):
        raw = read_raw_bids(bids_path=bids_fname, verbose=False)

    # test error message if electrodes is not a subset of Raw
    bids_path.update(root=tmpdir)
    write_raw_bids(raw, bids_path, 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)
    # popping off channels should not result in an error
    # however, a warning will be raised through mne-python
    with pytest.warns(RuntimeWarning,
                      match='DigMontage is '
                      'only a subset of info'):
        read_raw_bids(bids_path=bids_fname, verbose=False)

    # make sure montage is set if there are coordinates w/ 'n/a'
    raw.info['bads'] = []
    write_raw_bids(raw, bids_path, 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_path=bids_fname, 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']
Esempio n. 26
0
def test_handle_info_reading(tmpdir):
    """Test reading information from a BIDS sidecar JSON file."""
    # 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=tmpdir)
    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

    # setting line_freq to None should produce 'n/a' in the JSON sidecar
    raw.info['line_freq'] = None
    write_raw_bids(raw, bids_path, overwrite=True)
    raw = read_raw_bids(bids_path=bids_path)
    assert raw.info['line_freq'] is None

    with open(sidecar_fname, 'r', encoding='utf-8') as fin:
        sidecar_json = json.load(fin)
    assert sidecar_json["PowerLineFrequency"] == 'n/a'

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

    # check whether there are "Extra points" in raw.info['dig'] if
    # DigitizedHeadPoints is set to True and not otherwise
    n_dig_points = 0
    for dig_point in raw.info['dig']:
        if dig_point['kind'] == FIFF.FIFFV_POINT_EXTRA:
            n_dig_points += 1
    if sidecar_json['DigitizedHeadPoints']:
        assert n_dig_points > 0
    else:
        assert n_dig_points == 0

    # check whether any of NAS/LPA/RPA are present in raw.info['dig']
    # DigitizedLandmark is set to True, and False otherwise
    landmark_present = False
    for dig_point in raw.info['dig']:
        if dig_point['kind'] in [
                FIFF.FIFFV_POINT_LPA, FIFF.FIFFV_POINT_RPA,
                FIFF.FIFFV_POINT_NASION
        ]:
            landmark_present = True
            break
    if landmark_present:
        assert sidecar_json['DigitizedLandmarks'] is True
    else:
        assert sidecar_json['DigitizedLandmarks'] is False

    # 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`
    raw.info['line_freq'] = 60
    write_raw_bids(raw, bids_path, overwrite=True)
    deriv_dir = tmpdir.mkdir("derivatives")
    sidecar_copy = deriv_dir / op.basename(sidecar_fname)
    with open(sidecar_fname, "r", encoding='utf-8') 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.warns(RuntimeWarning, match="Defaulting to .* sidecar JSON"):
        raw = read_raw_bids(bids_path=bids_path)
        assert raw.info['line_freq'] == 55
Esempio n. 27
0
def test_get_head_mri_trans(tmpdir):
    """Test getting a trans object from BIDS data."""
    import nibabel as nib

    event_id = {
        'Auditory/Left': 1,
        'Auditory/Right': 2,
        'Visual/Left': 3,
        'Visual/Right': 4,
        'Smiley': 5,
        'Button': 32
    }
    events_fname = op.join(data_path, 'MEG', 'sample',
                           'sample_audvis_trunc_raw-eve.fif')

    # Drop unknown events.
    events = mne.read_events(events_fname)
    events = events[events[:, 2] != 0]

    # Write it to BIDS
    raw = _read_raw_fif(raw_fname)
    bids_path = _bids_path.copy().update(root=tmpdir)
    write_raw_bids(raw,
                   bids_path,
                   events_data=events,
                   event_id=event_id,
                   overwrite=False)

    # We cannot recover trans, if no MRI has yet been written
    with pytest.raises(RuntimeError):
        estimated_trans = get_head_mri_trans(bids_path=bids_path)

    # Write some MRI data and supply a `trans` so that a sidecar gets written
    trans = mne.read_trans(raw_fname.replace('_raw.fif', '-trans.fif'))

    # Get the T1 weighted MRI data file ... test write_anat with a nibabel
    # image instead of a file path
    t1w_mgh = op.join(data_path, 'subjects', 'sample', 'mri', 'T1.mgz')
    t1w_mgh = nib.load(t1w_mgh)

    t1w_bidspath = BIDSPath(subject=subject_id,
                            session=session_id,
                            acquisition=acq,
                            root=tmpdir)
    t1w_bidspath = write_anat(t1w_mgh,
                              bids_path=t1w_bidspath,
                              raw=raw,
                              trans=trans,
                              verbose=True)
    anat_dir = t1w_bidspath.directory

    # Try to get trans back through fitting points
    estimated_trans = get_head_mri_trans(bids_path=bids_path)

    assert trans['from'] == estimated_trans['from']
    assert trans['to'] == estimated_trans['to']
    assert_almost_equal(trans['trans'], estimated_trans['trans'])
    print(trans)
    print(estimated_trans)

    # provoke an error by introducing NaNs into MEG coords
    with pytest.raises(RuntimeError, match='AnatomicalLandmarkCoordinates'):
        raw.info['dig'][0]['r'] = np.ones(3) * np.nan
        sh.rmtree(anat_dir)
        bids_path = write_anat(t1w_mgh,
                               bids_path=t1w_bidspath,
                               raw=raw,
                               trans=trans,
                               verbose=True)
        estimated_trans = get_head_mri_trans(bids_path=bids_path)
Esempio n. 28
0
def test_handle_eeg_coords_reading(tmp_path):
    """Test reading iEEG coordinates from BIDS files."""
    bids_path = BIDSPath(
        subject=subject_id, session=session_id, run=run, acquisition=acq,
        task=task, root=tmp_path)

    data_path = op.join(testing.data_path(), 'EDF')
    raw_fname = op.join(data_path, 'test_reduced.edf')
    raw = _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.raises(RuntimeError, match="'head' coordinate frame "
                                           "must contain"):
        write_raw_bids(raw, bids_path, overwrite=True)

    bids_path.update(root=tmp_path)
    coordsystem_fname = _find_matching_sidecar(bids_path,
                                               suffix='coordsystem',
                                               extension='.json',
                                               on_error='warn')
    electrodes_fname = _find_matching_sidecar(bids_path,
                                              suffix='electrodes',
                                              extension='.tsv',
                                              on_error='warn')
    assert coordsystem_fname is None
    assert electrodes_fname is None

    # create montage in head frame and set should result in
    # an error if landmarks are not set
    montage = mne.channels.make_dig_montage(ch_pos=ch_pos,
                                            coord_frame="head")
    raw.set_montage(montage)
    with pytest.raises(RuntimeError, match="'head' coordinate frame "
                                           "must contain"):
        write_raw_bids(raw, bids_path, 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_path, overwrite=True)

    # obtain the sensor positions and assert ch_coords are same
    raw_test = read_raw_bids(bids_path, 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_path,
                                               suffix='coordsystem',
                                               extension='.json')
    _update_sidecar(coordsystem_fname, 'EEGCoordinateSystem', 'besa')
    with pytest.warns(RuntimeWarning, match='is not a BIDS-acceptable '
                                            'coordinate frame for EEG'):
        raw_test = read_raw_bids(bids_path)
        assert raw_test.info['dig'] is None