Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time-frequency in Source Space #6629

Closed
wants to merge 101 commits into from
Closed
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
101 commits
Select commit Hold shift + click to select a range
a65932f
Added SourceTFR
DiGyt Jun 6, 2019
dcd19e9
Added SourceTFR
DiGyt Jun 6, 2019
8e657c9
Added multitaper test
DiGyt Jun 6, 2019
9858b4f
added test
DiGyt Jun 10, 2019
c40b2e2
Read SourceEstimates into multitaper
DiGyt Jun 10, 2019
171d0c7
Merge branch 'SourceTFR' into source_multitaper
DiGyt Jun 10, 2019
14a5475
tfr_multitaper now takes VectorSourceEstimates without error
DiGyt Jun 13, 2019
b02bebc
updated SourceTFR with multitaper and morlet
DiGyt Jun 19, 2019
ca0a206
updated source tfr
DiGyt Jun 28, 2019
3ad3c1a
Merge https://github.com/mne-tools/mne-python into source_multit_wavelet
DiGyt Jun 28, 2019
636938b
added tests four SourceTFR
DiGyt Jul 3, 2019
b762647
fixed some stuff
DiGyt Jul 3, 2019
357b40d
Added Tests for source_tfr
DiGyt Jul 7, 2019
adab650
Made tfr(VectorSourceEstimate) and source_induced_power more equivalent
DiGyt Jul 9, 2019
e78ba3c
Merge https://github.com/mne-tools/mne-python into source_multit_wavelet
DiGyt Jul 12, 2019
6c8fd11
Merge https://github.com/mne-tools/mne-python into source_multit_wavelet
DiGyt Jul 12, 2019
cce9bd6
Tried to improve equivalence between morlet and source_induced_poewr
DiGyt Jul 13, 2019
05450f2
made one equivalent case for tfr_morlet and source_induced_power
DiGyt Jul 15, 2019
da783f2
add full_data param to apply_inverse_epochs
DiGyt Jul 16, 2019
90dbaec
cleaned up time_frequency
DiGyt Jul 16, 2019
0222eec
updated minimum_norm.time_frequency
DiGyt Jul 16, 2019
06cd6f0
adapted tfr_morlet(SourceEstimate) to source_induced_poewr
DiGyt Jul 19, 2019
3976049
prepared morlet, multitaper and stockwell for SourceEstimates
DiGyt Jul 24, 2019
0d908ef
enhanced tests for tfr
DiGyt Jul 26, 2019
bcb1f9f
read stc lists into tfr_functions
DiGyt Jul 29, 2019
dbf62c1
improved reading lists into tfr
DiGyt Jul 31, 2019
64dd51c
update to Kernel param for apply inverse branch
DiGyt Aug 1, 2019
f0df882
tfr_aux works now for everything
DiGyt Aug 2, 2019
eb1ab63
removed unused test
DiGyt Aug 2, 2019
bbe2479
stockwell works now with lists, itc
DiGyt Aug 2, 2019
7004958
cleaned up _tfr_loop_list
DiGyt Aug 3, 2019
99b8b1c
improved and parametrized tests, fixed bugs
DiGyt Aug 3, 2019
b3f8b21
added some tests for source_tfr
DiGyt Aug 3, 2019
ea5b12e
added Docstrings
DiGyt Aug 4, 2019
a88f875
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 4, 2019
900cf3f
corrected flake, pydocstyle
DiGyt Aug 4, 2019
8e4057e
corrected connectivity
DiGyt Aug 5, 2019
d0cc2bc
removed uneccesary format
DiGyt Aug 5, 2019
33dc256
changed some format diffs from master
DiGyt Aug 5, 2019
56c83fa
cleaned up SourceTFR + SourceTFR tests...
DiGyt Aug 5, 2019
e3a3cad
fixed pep & pydocstyle
DiGyt Aug 5, 2019
1113d63
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 5, 2019
bb4cb10
WIP: avoid modifying the doc
Aug 5, 2019
2f0b50b
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 6, 2019
c1d51b2
first review corrections
DiGyt Aug 6, 2019
d5f42ce
revert unedited files #1
DiGyt Aug 6, 2019
1119f51
revert unedited files #2
DiGyt Aug 6, 2019
cf2cfd7
revert unedited files #3
DiGyt Aug 6, 2019
00dcc73
revert unedited files #4
DiGyt Aug 6, 2019
c89cad3
reverting _brain.py manually
DiGyt Aug 6, 2019
8c0aef0
reverting view.py manually
DiGyt Aug 6, 2019
732a821
reverting epochs.py manually
DiGyt Aug 6, 2019
4d75ee5
reverting raw.py manually
DiGyt Aug 6, 2019
c53a657
reverting utils.py manually
DiGyt Aug 6, 2019
f9260f3
reverting plot_10_raw_overview.py manually
DiGyt Aug 6, 2019
905ac6e
tried to refactor _tfr_aux
DiGyt Aug 9, 2019
f831b88
set source_estimate to master to evade conflicts
DiGyt Aug 9, 2019
656cb20
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 9, 2019
2246b98
adapted source_estimate to changes in kernel_param_for_apply_inverse
DiGyt Aug 9, 2019
2fdca02
flake, pydocstyle
DiGyt Aug 9, 2019
e842af1
refactored _tfr_loop_list
DiGyt Aug 12, 2019
b245edb
introduced docs for _tfr_loop_list
DiGyt Aug 12, 2019
56e32cb
removed old doc in _tfr_loop_list
DiGyt Aug 12, 2019
4a6dada
Added SourceTFR to python_reference.rst
DiGyt Aug 15, 2019
3353b40
added SourceTFR to init.py
DiGyt Aug 15, 2019
26b3e07
try to fix SourceTFR reference Error
DiGyt Aug 15, 2019
6fd8ac7
try to fix SourceTFR verbose doc
DiGyt Aug 16, 2019
df75c14
try fixing missing reference for circle ci
DiGyt Aug 16, 2019
b28d04a
updated what's new
DiGyt Aug 16, 2019
92f47f9
Merge remote-tracking branch 'origin/source_into_tfr' into source_int…
DiGyt Aug 16, 2019
8be8052
reverted df75c14
DiGyt Aug 16, 2019
3048f55
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 18, 2019
bc8bb0a
reupdated whatsnew/ addded SourceTFR to conf.py
DiGyt Aug 18, 2019
84bb6ab
implemented faster cwt computation
DiGyt Aug 18, 2019
ac344ce
added test param for 'delayed=True' case equivalence
DiGyt Aug 18, 2019
dbac5ba
removed outdated comment
DiGyt Aug 18, 2019
6298fb1
fix flake
DiGyt Aug 18, 2019
c601c31
Enable tfr_stockwell to process lists/generators subsequently
DiGyt Aug 20, 2019
c8e1cb6
enabling tfr_stockwell to compute lists/gens subsequently
DiGyt Aug 20, 2019
b03b858
changed tests to also cover kernelized data
DiGyt Aug 20, 2019
9593f12
removed delayed tests from test_morlet_induced_power...
DiGyt Aug 20, 2019
e43619c
compute tfr_stockwell only on sensor data
DiGyt Aug 20, 2019
a34d150
flake, pydocstyle
DiGyt Aug 21, 2019
114d31d
refactor stockwell functions
DiGyt Aug 21, 2019
1ae38ec
small improvements
DiGyt Aug 21, 2019
65090e3
more small improvements
DiGyt Aug 21, 2019
c673a9d
renamed testing check function
DiGyt Aug 21, 2019
f04eca5
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 22, 2019
fb5b733
use random state instead of random seed
DiGyt Aug 22, 2019
3536af7
changed sourceTFR data docstring/comments
DiGyt Aug 22, 2019
ba7e8d7
added authur + licensing
DiGyt Aug 22, 2019
9e98707
manually merged what's new / changes
DiGyt Aug 22, 2019
3ac8e02
changed indentation in docstring
DiGyt Aug 22, 2019
9656534
Merge branch 'master' into source_into_tfr
DiGyt Aug 25, 2019
8e6a9e0
fixed vertices function in order to avoid __repr__ and plotting error
DiGyt Aug 30, 2019
7c78010
Merge branch 'master' into source_into_tfr
DiGyt Aug 30, 2019
3256746
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Aug 30, 2019
e9ad48c
fix flake
DiGyt Aug 30, 2019
966af7a
Merge https://github.com/mne-tools/mne-python into source_into_tfr
DiGyt Sep 3, 2019
c25dc4c
migrated source_tfr...
DiGyt Sep 3, 2019
b8daad8
not load SourceTFR in time_frequency.__init__
DiGyt Sep 3, 2019
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
40 changes: 29 additions & 11 deletions mne/minimum_norm/inverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -1071,12 +1071,19 @@ def apply_inverse_raw(raw, inverse_operator, lambda2, method="dSPM",
def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method='dSPM',
label=None, nave=1, pick_ori=None,
prepared=False, method_params=None,
verbose=None):
delayed=False, verbose=None):
"""Generate inverse solutions for epochs. Used in apply_inverse_epochs."""
_check_option('method', method, INVERSE_METHODS)
_check_ori(pick_ori, inverse_operator['source_ori'])
_check_ch_names(inverse_operator, epochs.info)

is_free_ori = not (is_fixed_orient(inverse_operator) or
pick_ori == 'normal')

if delayed and is_free_ori and pick_ori != "vector":
raise ValueError("delayed must be False for free orientations other "
"than pick_ori='vector'.")

#
# Set up the inverse according to the parameters
#
Expand All @@ -1095,13 +1102,10 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method='dSPM',
tstep = 1.0 / epochs.info['sfreq']
tmin = epochs.times[0]

is_free_ori = not (is_fixed_orient(inverse_operator) or
pick_ori == 'normal')

if pick_ori == 'vector' and noise_norm is not None:
noise_norm = noise_norm.repeat(3, axis=0)

if not is_free_ori and noise_norm is not None:
if not (is_free_ori and pick_ori != 'vector') and noise_norm is not None:
# premultiply kernel with noise normalization
K *= noise_norm

Expand All @@ -1116,15 +1120,16 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method='dSPM',
# Compute solution and combine current components (non-linear)
sol = np.dot(K, e[sel]) # apply imaging kernel

if pick_ori != 'vector':
logger.info('combining the current components...')
sol = combine_xyz(sol)
if is_free_ori and pick_ori != 'vector':
logger.info('combining the current components...')
sol = combine_xyz(sol)

if noise_norm is not None:
sol *= noise_norm

else:
# Linear inverse: do computation here or delayed
if len(sel) < K.shape[1]:
if delayed:
sol = (K, e[sel])
else:
sol = np.dot(K, e[sel])
Expand All @@ -1143,7 +1148,7 @@ def _apply_inverse_epochs_gen(epochs, inverse_operator, lambda2, method='dSPM',
def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
label=None, nave=1, pick_ori=None,
return_generator=False, prepared=False,
method_params=None, verbose=None):
method_params=None, delayed=False, verbose=None):
"""Apply inverse operator to Epochs.

Parameters
Expand Down Expand Up @@ -1179,6 +1184,19 @@ def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
Additional options for eLORETA. See Notes of :func:`apply_inverse`.

.. versionadded:: 0.16
delayed : bool
If False, the source time courses are computed. If True, they are
stored as a tuple of two smaller arrays in order to save memory. In
this case, the first array in the tuple corresponds to the "kernel"
shape (n_vertices [, n_orientations], n_sensors) and the second array
to the "sens_data" shape (n_sensors, n_times). The full source time
courses field will be automatically computed when stc.data is called
for the first time (see for example: :class:`mne.SourceEstimate`).
`delayed=True` is only implemented for fixed orientations (e.g.
from pick_ori = "normal") as well as pick_ori="vector".
Defaults to False.

.. versionadded:: 0.19
%(verbose)s

Returns
Expand All @@ -1194,7 +1212,7 @@ def apply_inverse_epochs(epochs, inverse_operator, lambda2, method="dSPM",
stcs = _apply_inverse_epochs_gen(
epochs, inverse_operator, lambda2, method=method, label=label,
nave=nave, pick_ori=pick_ori, verbose=verbose, prepared=prepared,
method_params=method_params)
method_params=method_params, delayed=delayed)

if not return_generator:
# return a list
Expand Down
52 changes: 46 additions & 6 deletions mne/minimum_norm/tests/test_inverse.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,12 +781,9 @@ def test_apply_mne_inverse_fixed_raw():
assert_array_almost_equal(stc.data, stc3.data)


@testing.requires_testing_data
def test_apply_mne_inverse_epochs():
"""Test MNE with precomputed inverse operator on Epochs."""
inverse_operator = read_inverse_operator(fname_full)
label_lh = read_label(fname_label % 'Aud-lh')
label_rh = read_label(fname_label % 'Aud-rh')
@pytest.fixture
def epochs():
"""Create an epochs object used for testing."""
event_id, tmin, tmax = 1, -0.2, 0.5
raw = read_raw_fif(fname_raw)

Expand All @@ -799,6 +796,16 @@ def test_apply_mne_inverse_epochs():
epochs = Epochs(raw, events, event_id, tmin, tmax, picks=picks,
baseline=(None, 0), reject=reject, flat=flat)

return epochs


@testing.requires_testing_data
def test_apply_mne_inverse_epochs(epochs):
"""Test MNE with precomputed inverse operator on Epochs."""
inverse_operator = read_inverse_operator(fname_full)
label_lh = read_label(fname_label % 'Aud-lh')
label_rh = read_label(fname_label % 'Aud-rh')

inverse_operator = prepare_inverse_operator(inverse_operator, nave=1,
lambda2=lambda2,
method="dSPM")
Expand Down Expand Up @@ -891,4 +898,37 @@ def test_inverse_ctf_comp():
apply_inverse_raw(raw, inv, 1. / 9.)


def _check_delayed_data(inst, delayed):
"""Check whether data is represented as kernel or not."""
if delayed:
assert isinstance(inst._kernel, np.ndarray)
assert isinstance(inst._sens_data, np.ndarray)
assert inst._data is None
assert not inst._kernel_removed
else:
assert inst._kernel is None
assert inst._sens_data is None
assert isinstance(inst._data, np.ndarray)


@testing.requires_testing_data
@pytest.mark.parametrize('pick_ori', ['normal', 'vector'])
def test_delayed_data(epochs, pick_ori):
"""Test if kernel in apply_inverse_epochs was properly applied."""
inverse_operator = read_inverse_operator(fname_full)
inverse_operator = prepare_inverse_operator(inverse_operator, nave=1,
lambda2=lambda2,
method="dSPM")

full_stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2,
pick_ori=pick_ori, delayed=False)
kernel_stcs = apply_inverse_epochs(epochs, inverse_operator, lambda2,
pick_ori=pick_ori, delayed=True)

for full_stc, kern_stc in zip(full_stcs, kernel_stcs):
_check_delayed_data(full_stc, delayed=False)
_check_delayed_data(kern_stc, delayed=True)
assert_allclose(kern_stc.data, full_stc.data)


run_tests_if_main()
12 changes: 11 additions & 1 deletion mne/source_estimate.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,12 @@ def _make_stc(data, vertices, src_type=None, tmin=None, tstep=None,
src_type = _get_src_type(src=None, vertices=vertices,
warn_text=warn_text)

if vector and isinstance(data, tuple):
kernel = True
data, sens_data = data[0], data[1]
else:
kernel = False

if src_type == 'surface':
# make a surface source estimate
n_vertices = len(vertices[0]) + len(vertices[1])
Expand All @@ -401,6 +407,8 @@ def _make_stc(data, vertices, src_type=None, tmin=None, tstep=None,
for i, d, n in zip(range(data.shape[0]), data, source_nn):
data_rot[i] = np.dot(n.T, d)
data = data_rot
if kernel:
data = (data, sens_data)
stc = VectorSourceEstimate(data, vertices=vertices, tmin=tmin,
tstep=tstep, subject=subject)
else:
Expand All @@ -412,6 +420,8 @@ def _make_stc(data, vertices, src_type=None, tmin=None, tstep=None,
klass = VolVectorSourceEstimate
else:
klass = VolSourceEstimate
if kernel:
data = (data, sens_data)
stc = klass(data, vertices=vertices, tmin=tmin, tstep=tstep,
subject=subject)
elif src_type == 'mixed':
Expand Down Expand Up @@ -491,7 +501,7 @@ def __init__(self, data, vertices=None, tmin=None, tstep=None,
raise ValueError('If data is a tuple it has to be length 2')
kernel, sens_data = data
data = None
if kernel.shape[1] != sens_data.shape[0]:
if kernel.shape[-1] != sens_data.shape[0]:
raise ValueError('kernel and sens_data have invalid '
'dimensions')
if sens_data.ndim != 2:
Expand Down
Loading