File: test_resolution_metrics.py

package info (click to toggle)
python-mne 1.3.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 100,172 kB
  • sloc: python: 166,349; pascal: 3,602; javascript: 1,472; sh: 334; makefile: 236
file content (145 lines) | stat: -rw-r--r-- 6,777 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# -*- coding: utf-8 -*-
# Authors: Olaf Hauk <olaf.hauk@mrc-cbu.cam.ac.uk>
#          Daniel McCloy <dan.mccloy@gmail.com>
#
# License: BSD-3-Clause
"""
Test the following properties for resolution metrics.

Peak localisation error of MNE is the same for PSFs and CTFs.
Peak localisation error of sLORETA for PSFs is zero.
Currently only for fixed source orientations.
"""

import os.path as op
import numpy as np
import pytest
from numpy.testing import (assert_array_almost_equal, assert_array_equal,
                           assert_)

import mne
from mne.datasets import testing
from mne.minimum_norm.resolution_matrix import make_inverse_resolution_matrix
from mne.minimum_norm.spatial_resolution import (resolution_metrics,
                                                 _rectify_resolution_matrix)

data_path = testing.data_path(download=False)
subjects_dir = op.join(data_path, 'subjects')
fname_inv = op.join(data_path, 'MEG', 'sample',
                    'sample_audvis_trunc-meg-eeg-oct-6-meg-inv.fif')
fname_evoked = op.join(data_path, 'MEG', 'sample',
                       'sample_audvis_trunc-ave.fif')
fname_fwd = op.join(data_path, 'MEG', 'sample',
                    'sample_audvis_trunc-meg-eeg-oct-4-fwd.fif')
fname_cov = op.join(data_path, 'MEG', 'sample', 'sample_audvis_trunc-cov.fif')


@testing.requires_testing_data
def test_resolution_metrics_surface():
    """Test resolution metrics on surfaces."""
    fwd = mne.read_forward_solution(fname_fwd)
    # forward operator with fixed source orientations
    fwd = mne.convert_forward_solution(fwd, surf_ori=True,
                                       force_fixed=True, copy=False)

    # noise covariance matrix
    noise_cov = mne.read_cov(fname_cov)
    # evoked data for info
    evoked = mne.read_evokeds(fname_evoked, 0)

    # fixed source orientation
    inv = mne.minimum_norm.make_inverse_operator(
        info=evoked.info, forward=fwd, noise_cov=noise_cov, loose=0.,
        depth=None, fixed=True)

    # regularisation parameter based on SNR
    snr = 3.0
    lambda2 = 1.0 / snr ** 2
    # resolution matrices for fixed source orientation
    # compute resolution matrix for MNE
    rm_mne = make_inverse_resolution_matrix(fwd, inv,
                                            method='MNE', lambda2=lambda2)
    # compute very smooth MNE
    rm_mne_smooth = make_inverse_resolution_matrix(fwd, inv,
                                                   method='MNE', lambda2=100.)
    # compute resolution matrix for sLORETA
    rm_lor = make_inverse_resolution_matrix(fwd, inv,
                                            method='sLORETA', lambda2=lambda2)

    # Compute localisation error (STCs)
    # Peak
    le_mne_psf = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                    metric='peak_err')
    le_mne_ctf = resolution_metrics(rm_mne, fwd['src'], function='ctf',
                                    metric='peak_err')
    le_lor_psf = resolution_metrics(rm_lor, fwd['src'], function='psf',
                                    metric='peak_err')
    # Centre-of-gravity
    cog_mne_psf = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                     metric='cog_err')
    cog_mne_ctf = resolution_metrics(rm_mne, fwd['src'], function='ctf',
                                     metric='cog_err')

    # Compute spatial spread (STCs)
    # Spatial deviation
    sd_mne_psf = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                    metric='sd_ext')
    sd_mne_psf_smooth = resolution_metrics(rm_mne_smooth, fwd['src'],
                                           function='psf',
                                           metric='sd_ext')
    sd_mne_ctf = resolution_metrics(rm_mne, fwd['src'], function='ctf',
                                    metric='sd_ext')
    sd_lor_ctf = resolution_metrics(rm_lor, fwd['src'], function='ctf',
                                    metric='sd_ext')
    # Maximum radius
    mr_mne_psf = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                    metric='maxrad_ext', threshold=0.6)
    mr_mne_psf_smooth = resolution_metrics(rm_mne_smooth, fwd['src'],
                                           function='psf', metric='maxrad_ext',
                                           threshold=0.6)
    mr_mne_ctf = resolution_metrics(rm_mne, fwd['src'], function='ctf',
                                    metric='maxrad_ext', threshold=0.6)
    mr_lor_ctf = resolution_metrics(rm_lor, fwd['src'], function='ctf',
                                    metric='maxrad_ext', threshold=0.6)
    # lower threshold -> larger spatial extent
    mr_mne_psf_0 = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                      metric='maxrad_ext', threshold=0.)
    mr_mne_psf_9 = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                      metric='maxrad_ext', threshold=0.9)

    # Compute relative amplitude (STCs)
    ra_mne_psf = resolution_metrics(rm_mne, fwd['src'], function='psf',
                                    metric='peak_amp')
    ra_mne_ctf = resolution_metrics(rm_mne, fwd['src'], function='ctf',
                                    metric='peak_amp')

    # Tests
    with pytest.raises(ValueError, match='is not a recognized metric'):
        resolution_metrics(rm_mne, fwd['src'], function='psf', metric='foo')
    with pytest.raises(ValueError, match='a recognised resolution function'):
        resolution_metrics(rm_mne, fwd['src'], function='foo',
                           metric='peak_err')

    # For MNE: PLE for PSF and CTF equal?
    assert_array_almost_equal(le_mne_psf.data, le_mne_ctf.data)
    assert_array_almost_equal(cog_mne_psf.data, cog_mne_ctf.data)
    # For MNE: SD and maxrad for PSF and CTF equal?
    assert_array_almost_equal(sd_mne_psf.data, sd_mne_ctf.data)
    assert_array_almost_equal(mr_mne_psf.data, mr_mne_ctf.data)
    assert_((mr_mne_psf_0.data > mr_mne_psf_9.data).all())
    # For MNE: RA for PSF and CTF equal?
    assert_array_almost_equal(ra_mne_psf.data, ra_mne_ctf.data)
    # Zero PLE for sLORETA?
    assert_((le_lor_psf.data == 0.).all())
    # Spatial deviation and maxrad of CTFs for MNE and sLORETA equal?
    assert_array_almost_equal(sd_mne_ctf.data, sd_lor_ctf.data)
    assert_array_almost_equal(mr_mne_ctf.data, mr_lor_ctf.data)
    # Smooth MNE has larger spatial extent?
    assert_(np.sum(sd_mne_psf_smooth.data) > np.sum(sd_mne_psf.data))
    assert_(np.sum(mr_mne_psf_smooth.data) > np.sum(mr_mne_psf.data))

    # test "rectification" of resolution matrix
    r1 = np.ones([8, 4])
    r2 = _rectify_resolution_matrix(r1)

    assert_array_equal(r2, np.sqrt(2) * np.ones((4, 4)))