Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/changes/latest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ Enhancements

- Add :func:`mne.preprocessing.ieeg.project_sensors_onto_brain` to project ECoG sensors onto the pial surface to compensate for brain shift (:gh:`9800` by `Alex Rockhill`_)

- Add support for data acquired with NIRx devices using Aurora software version 2021.9 (:gh:`9800` by `Robert Luke`_, and `Eric Larson`_)

- All functions for reading and writing files should now automatically handle ``~`` (the tilde character) and expand it to the user's home directory. Should you come across any function that doesn't do it, please do let us know! (:gh:`9613` by `Richard Höchenberger`_)

- All functions accepting a FreeSurfer subjects directory via a ``subjects_dir`` parameter can now consume :py:class:`pathlib.Path` objects too (used to be only strings) (:gh:`9613` by `Richard Höchenberger`_)
Expand Down
4 changes: 2 additions & 2 deletions mne/datasets/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
# respective repos, and make a new release of the dataset on GitHub. Then
# update the checksum in the MNE_DATASETS dict below, and change version
# here: ↓↓↓↓↓ ↓↓↓
RELEASES = dict(testing='0.123', misc='0.23')
RELEASES = dict(testing='0.125', misc='0.23')
TESTING_VERSIONED = f'mne-testing-data-{RELEASES["testing"]}'
MISC_VERSIONED = f'mne-misc-data-{RELEASES["misc"]}'

Expand Down Expand Up @@ -307,7 +307,7 @@

MNE_DATASETS['testing'] = dict(
archive_name=f'{TESTING_VERSIONED}.tar.gz', # 'mne-testing-data',
hash='md5:db07710c0b94476f954f60926685b5b7',
hash='md5:0871ae325805a9cd2cdfb2fc74327abb',
url=('https://codeload.github.com/mne-tools/mne-testing-data/'
f'tar.gz/{RELEASES["testing"]}'),
folder_name='MNE-testing-data',
Expand Down
13 changes: 8 additions & 5 deletions mne/io/nirx/nirx.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ def __init__(self, fname, saturated, preload=False, verbose=None):
# Check that the file format version is supported
if is_aurora:
# We may need to ease this requirement back
if hdr['GeneralInfo']['Version'] not in ['2021.4.0-34-ge9fdbbc8']:
if hdr['GeneralInfo']['Version'] not in ['2021.4.0-34-ge9fdbbc8',
'2021.9.0-5-g3eb32851']:
warn("MNE has not been tested with Aurora version "
f"{hdr['GeneralInfo']['Version']}")
else:
Expand All @@ -185,7 +186,8 @@ def __init__(self, fname, saturated, preload=False, verbose=None):
meas_date = None
# Several formats have been observed so we try each in turn
for dt_code in ['"%a, %b %d, %Y""%H:%M:%S.%f"',
'"%a, %d %b %Y""%H:%M:%S.%f"']:
'"%a, %d %b %Y""%H:%M:%S.%f"',
'%Y-%m-%d %H:%M:%S.%f']:
try:
meas_date = dt.datetime.strptime(datetime_str, dt_code)
meas_date = meas_date.replace(tzinfo=dt.timezone.utc)
Expand Down Expand Up @@ -271,9 +273,10 @@ def __init__(self, fname, saturated, preload=False, verbose=None):
subject_info['sex'] = FIFF.FIFFV_SUBJ_SEX_FEMALE
else:
subject_info['sex'] = FIFF.FIFFV_SUBJ_SEX_UNKNOWN
subject_info['birthday'] = (meas_date.year - int(inf['age']),
meas_date.month,
meas_date.day)
if inf['age'] != '':
subject_info['birthday'] = (meas_date.year - int(inf['age']),
meas_date.month,
meas_date.day)

# Read information about probe/montage/optodes
# A word on terminology used here:
Expand Down
19 changes: 15 additions & 4 deletions mne/io/nirx/tests/test_nirx.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,24 @@
nirsport2_snirf = op.join(data_path(download=False), 'SNIRF', 'NIRx',
'NIRSport2', '1.0.3', '2021-05-05_001.snirf')

nirsport2_2021_9 = op.join(data_path(download=False), 'NIRx', 'nirsport_v2',
'aurora_2021_9')
snirf_nirsport2_20219 = op.join(data_path(download=False),
'SNIRF', 'NIRx', 'NIRSport2', '2021.9',
'2021-10-01_002.snirf')


@requires_h5py
@requires_testing_data
@pytest.mark.filterwarnings('ignore:.*Extraction of measurement.*:')
def test_nirsport_v2_matches_snirf():
@pytest.mark.parametrize('fname_nirx, fname_snirf', (
[nirsport2, nirsport2_snirf],
[nirsport2_2021_9, snirf_nirsport2_20219],
))
def test_nirsport_v2_matches_snirf(fname_nirx, fname_snirf):
"""Test NIRSport2 raw files return same data as snirf."""
raw = read_raw_nirx(nirsport2, preload=True)
raw_snirf = read_raw_snirf(nirsport2_snirf, preload=True)
raw = read_raw_nirx(fname_nirx, preload=True)
raw_snirf = read_raw_snirf(fname_snirf, preload=True)

assert_allclose(raw._data, raw_snirf._data)

Expand Down Expand Up @@ -559,7 +569,8 @@ def test_nirx_15_0():
@pytest.mark.parametrize('fname, boundary_decimal', (
[fname_nirx_15_2_short, 1],
[fname_nirx_15_2, 0],
[fname_nirx_15_0, 0]
[fname_nirx_15_2, 0],
[nirsport2_2021_9, 0]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is erroring (see below), as with my other comment are these standard tests an issue? Should I be adding each test file to this list?


mne/io/nirx/tests/test_nirx.py:567 (test_nirx_standard[/Users/rluke/mne_data/MNE-testing-data/NIRx/nirsport_v2/aurora_2021_9-0])
test_nirx.py:577: in test_nirx_standard
    _test_raw_reader(read_raw_nirx, fname=fname,
../../tests/test_raw.py:283: in _test_raw_reader
    assert_array_almost_equal(raw.times, raw3.times)
E   AssertionError: 
E   Arrays are not almost equal to 6 decimals
E   
E   Mismatched elements: 2273 / 2762 (82.3%)
E   Max absolute difference: 8.48179172e-06
E   Max relative difference: 3.12500002e-08
E    x: array([0.000000e+00, 9.830400e-02, 1.966080e-01, ..., 2.712207e+02,
E          2.713190e+02, 2.714173e+02])
E    y: array([0.000000e+00, 9.830400e-02, 1.966080e-01, ..., 2.712207e+02,
E          2.713190e+02, 2.714173e+02])

))
def test_nirx_standard(fname, boundary_decimal):
"""Test standard operations."""
Expand Down
22 changes: 18 additions & 4 deletions mne/io/snirf/tests/test_snirf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
nirx_nirsport2_103_2 = op.join(data_path(download=False),
'SNIRF', 'NIRx', 'NIRSport2', '1.0.3',
'2021-05-05_001.snirf')
snirf_nirsport2_20219 = op.join(data_path(download=False),
'SNIRF', 'NIRx', 'NIRSport2', '2021.9',
'2021-10-01_002.snirf')
nirx_nirsport2_20219 = op.join(data_path(download=False), 'NIRx',
'nirsport_v2', 'aurora_2021_9')


@requires_h5py
Expand All @@ -45,7 +50,8 @@
nirx_nirsport2_103,
sfnirs_homer_103_153,
nirx_nirsport2_103,
nirx_nirsport2_103_2]))
nirx_nirsport2_103_2,
snirf_nirsport2_20219]))
def test_basic_reading_and_min_process(fname):
"""Test reading SNIRF files and minimum typical processing."""
raw = read_raw_snirf(fname, preload=True)
Expand Down Expand Up @@ -284,10 +290,18 @@ def test_snirf_nirsport2_w_positions():

@requires_testing_data
@requires_h5py
def test_snirf_standard():
@pytest.mark.parametrize('fname, boundary_decimal, test_scaling, test_rank', (
[sfnirs_homer_103_wShort, 0, True, True],
[nirx_nirsport2_103, 0, True, False], # strange rank behavior
[nirx_nirsport2_103_2, 0, False, True], # weirdly small values
[snirf_nirsport2_20219, 0, True, True],
))
def test_snirf_standard(fname, boundary_decimal, test_scaling, test_rank):
"""Test standard operations."""
_test_raw_reader(read_raw_snirf, fname=sfnirs_homer_103_wShort,
boundary_decimal=0) # low fs
_test_raw_reader(read_raw_snirf, fname=fname,
boundary_decimal=boundary_decimal,
test_scaling=test_scaling,
test_rank=test_rank) # low fs


@requires_testing_data
Expand Down
15 changes: 9 additions & 6 deletions mne/io/tests/test_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,15 +200,18 @@ def _test_raw_reader(reader, test_preloading=True, test_kwargs=True,
# ranks should all be reduced by 1
if test_rank == 'less':
cmp = np.less
else:
elif test_rank is False:
cmp = None
else: # anything else is like True or 'equal'
assert test_rank is True or test_rank == 'equal', test_rank
cmp = np.equal
rank_load_apply_get = np.linalg.matrix_rank(data_load_apply_get)
rank_apply_get = np.linalg.matrix_rank(data_apply_get)
rank_apply_load_get = np.linalg.matrix_rank(data_apply_load_get)
rank_apply_load_get = np.linalg.matrix_rank(data_apply_load_get)
assert cmp(rank_load_apply_get, len(col_names) - 1)
assert cmp(rank_apply_get, len(col_names) - 1)
assert cmp(rank_apply_load_get, len(col_names) - 1)
if cmp is not None:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @larsoner I am much happier having you make this internal change than me. Appreciate your effort

assert cmp(rank_load_apply_get, len(col_names) - 1)
assert cmp(rank_apply_get, len(col_names) - 1)
assert cmp(rank_apply_load_get, len(col_names) - 1)
# and they should all match
t_kw = dict(
atol=atol, err_msg='before != after, likely _mult_cal_one prob')
Expand Down Expand Up @@ -280,7 +283,7 @@ def _test_raw_reader(reader, test_preloading=True, test_kwargs=True,
assert set(raw.info.keys()) == set(raw3.info.keys())
assert_allclose(raw3[0:20][0], full_data[0:20], rtol=1e-6,
atol=1e-20) # atol is very small but > 0
assert_array_almost_equal(raw.times, raw3.times)
assert_allclose(raw.times, raw3.times, atol=1e-6, rtol=1e-6)

assert not math.isnan(raw3.info['highpass'])
assert not math.isnan(raw3.info['lowpass'])
Expand Down