def test_make_dics(tmpdir, _load_forward, idx, whiten): """Test making DICS beamformer filters.""" # We only test proper handling of parameters here. Testing the results is # done in test_apply_dics_timeseries and test_apply_dics_csd. fwd_free, fwd_surf, fwd_fixed, fwd_vol = _load_forward epochs, _, csd, _, label, vertices, source_ind = \ _simulate_data(fwd_fixed, idx) with pytest.raises(ValueError, match='several sensor types'): make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None) if whiten: noise_csd, rank = _make_rand_csd(epochs.info, csd) assert rank == len(epochs.info['ch_names']) == 62 else: noise_csd = None epochs.pick_types(meg='grad') with pytest.raises(ValueError, match="Invalid value for the 'pick_ori'"): make_dics(epochs.info, fwd_fixed, csd, pick_ori="notexistent", noise_csd=noise_csd) with pytest.raises(ValueError, match='rank, if str'): make_dics(epochs.info, fwd_fixed, csd, rank='foo', noise_csd=noise_csd) with pytest.raises(TypeError, match='rank must be'): make_dics(epochs.info, fwd_fixed, csd, rank=1., noise_csd=noise_csd) # Test if fixed forward operator is detected when picking normal # orientation with pytest.raises(ValueError, match='forward operator with free ori'): make_dics(epochs.info, fwd_fixed, csd, pick_ori="normal", noise_csd=noise_csd) # Test if non-surface oriented forward operator is detected when picking # normal orientation with pytest.raises(ValueError, match='oriented in surface coordinates'): make_dics(epochs.info, fwd_free, csd, pick_ori="normal", noise_csd=noise_csd) # Test if volume forward operator is detected when picking normal # orientation with pytest.raises(ValueError, match='oriented in surface coordinates'): make_dics(epochs.info, fwd_vol, csd, pick_ori="normal", noise_csd=noise_csd) # Test invalid combinations of parameters with pytest.raises(ValueError, match='reduce_rank cannot be used with'): make_dics(epochs.info, fwd_free, csd, inversion='single', reduce_rank=True, noise_csd=noise_csd) # TODO: Restore this? # with pytest.raises(ValueError, match='not stable with depth'): # make_dics(epochs.info, fwd_free, csd, weight_norm='unit-noise-gain', # inversion='single', depth=None) # Sanity checks on the returned filters n_freq = len(csd.frequencies) vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno']) n_verts = len(vertices) n_orient = 3 n_channels = len(epochs.ch_names) # Test return values weight_norm = 'unit-noise-gain' inversion = 'single' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, real_filter=False, noise_csd=noise_csd, inversion=inversion) assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert np.iscomplexobj(filters['weights']) assert filters['csd'].ch_names == epochs.ch_names assert isinstance(filters['csd'], CrossSpectralDensity) assert filters['ch_names'] == epochs.ch_names assert_array_equal(filters['proj'], np.eye(n_channels)) assert_array_equal(filters['vertices'][0], vertices) assert_array_equal(filters['vertices'][1], []) # Label was on the LH assert filters['subject'] == fwd_free['src']._subject assert filters['pick_ori'] is None assert filters['is_free_ori'] assert filters['inversion'] == inversion assert filters['weight_norm'] == weight_norm assert 'DICS' in repr(filters) assert 'subject "sample"' in repr(filters) assert str(len(vertices)) in repr(filters) assert str(n_channels) in repr(filters) assert 'rank' not in repr(filters) _, noise_cov = _prepare_noise_csd(csd, noise_csd, real_filter=False) _, _, _, _, G, _, _, _ = _prepare_beamformer_input( epochs.info, fwd_surf, label, 'vector', combine_xyz=False, exp=None, noise_cov=noise_cov) G.shape = (n_channels, n_verts, n_orient) G = G.transpose(1, 2, 0).conj() # verts, orient, ch _assert_weight_norm(filters, G) inversion = 'matrix' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) _assert_weight_norm(filters, G) weight_norm = 'unit-noise-gain-invariant' inversion = 'single' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) _assert_weight_norm(filters, G) # Test picking orientations. Also test weight norming under these different # conditions. weight_norm = 'unit-noise-gain' filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert not filters['is_free_ori'] _assert_weight_norm(filters, G) filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm=weight_norm, depth=None, noise_csd=noise_csd, inversion=inversion) n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert not filters['is_free_ori'] _assert_weight_norm(filters, G) # From here on, only work on a single frequency csd = csd[0] # Test using a real-valued filter filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', real_filter=True, noise_csd=noise_csd) assert not np.iscomplexobj(filters['weights']) # Test forward normalization. When inversion='single', the power of a # unit-noise CSD should be 1, even without weight normalization. if not whiten: csd_noise = csd.copy() inds = np.triu_indices(csd.n_channels) # Using [:, :] syntax for in-place broadcasting csd_noise._data[:, :] = np.eye(csd.n_channels)[inds][:, np.newaxis] filters = make_dics(epochs.info, fwd_surf, csd_noise, label=label, weight_norm=None, depth=1., noise_csd=noise_csd, inversion='single') w = filters['weights'][0][:3] assert_allclose(np.diag(w.dot(w.conjugate().T)), 1.0, rtol=1e-6, atol=0) # Test turning off both forward and weight normalization filters = make_dics(epochs.info, fwd_surf, csd, label=label, weight_norm=None, depth=None, noise_csd=noise_csd) w = filters['weights'][0][:3] assert not np.allclose(np.diag(w.dot(w.conjugate().T)), 1.0, rtol=1e-2, atol=0) # Test neural-activity-index weight normalization. It should be a scaled # version of the unit-noise-gain beamformer. filters_nai = make_dics( epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm='nai', depth=None, noise_csd=noise_csd) w_nai = filters_nai['weights'][0] filters_ung = make_dics( epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm='unit-noise-gain', depth=None, noise_csd=noise_csd) w_ung = filters_ung['weights'][0] assert_allclose(np.corrcoef(np.abs(w_nai).ravel(), np.abs(w_ung).ravel()), 1, atol=1e-7) # Test whether spatial filter contains src_type assert 'src_type' in filters fname = op.join(str(tmpdir), 'filters-dics.h5') filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) for key in ['tmin', 'tmax']: # deal with strictness of object_diff setattr(filters['csd'], key, np.float64(getattr(filters['csd'], key))) assert object_diff(filters, filters_read) == ''
def test_make_lcmv(tmpdir, reg, proj): """Test LCMV with evoked data and single trials.""" raw, epochs, evoked, data_cov, noise_cov, label, forward,\ forward_surf_ori, forward_fixed, forward_vol = _get_data(proj=proj) for fwd in [forward, forward_vol]: filters = make_lcmv(evoked.info, fwd, data_cov, reg=reg, noise_cov=noise_cov) stc = apply_lcmv(evoked, filters, max_ori_out='signed') stc.crop(0.02, None) stc_pow = np.sum(np.abs(stc.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc.data[idx] tmax = stc.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.15, tmax assert 0.9 < np.max(max_stc) < 3.5, np.max(max_stc) if fwd is forward: # Test picking normal orientation (surface source space only). filters = make_lcmv(evoked.info, forward_surf_ori, data_cov, reg=reg, noise_cov=noise_cov, pick_ori='normal', weight_norm=None) stc_normal = apply_lcmv(evoked, filters, max_ori_out='signed') stc_normal.crop(0.02, None) stc_pow = np.sum(np.abs(stc_normal.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc_normal.data[idx] tmax = stc_normal.times[np.argmax(max_stc)] lower = 0.04 if proj else 0.025 assert lower < tmax < 0.14, tmax lower = 3e-7 if proj else 2e-7 assert lower < np.max(max_stc) < 3e-6, np.max(max_stc) # No weight normalization was applied, so the amplitude of normal # orientation results should always be smaller than free # orientation results. assert (np.abs(stc_normal.data) <= stc.data).all() # Test picking source orientation maximizing output source power filters = make_lcmv(evoked.info, fwd, data_cov, reg=reg, noise_cov=noise_cov, pick_ori='max-power') stc_max_power = apply_lcmv(evoked, filters, max_ori_out='signed') stc_max_power.crop(0.02, None) stc_pow = np.sum(np.abs(stc_max_power.data), axis=1) idx = np.argmax(stc_pow) max_stc = np.abs(stc_max_power.data[idx]) tmax = stc.times[np.argmax(max_stc)] lower = 0.08 if proj else 0.04 assert lower < tmax < 0.15, tmax assert 0.8 < np.max(max_stc) < 3., np.max(max_stc) stc_max_power.data[:, :] = np.abs(stc_max_power.data) if fwd is forward: # Maximum output source power orientation results should be # similar to free orientation results in areas with channel # coverage label = mne.read_label(fname_label) mean_stc = stc.extract_label_time_course(label, fwd['src'], mode='mean') mean_stc_max_pow = \ stc_max_power.extract_label_time_course(label, fwd['src'], mode='mean') assert_array_less(np.abs(mean_stc - mean_stc_max_pow), 1.0) # Test NAI weight normalization: filters = make_lcmv(evoked.info, fwd, data_cov, reg=reg, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai') stc_nai = apply_lcmv(evoked, filters, max_ori_out='signed') stc_nai.crop(0.02, None) # Test whether unit-noise-gain solution is a scaled version of NAI pearsoncorr = np.corrcoef(np.concatenate(np.abs(stc_nai.data)), np.concatenate(stc_max_power.data)) assert_almost_equal(pearsoncorr[0, 1], 1.) # Test if spatial filter contains src_type assert 'src_type' in filters # __repr__ assert len(evoked.ch_names) == 22 assert len(evoked.info['projs']) == (3 if proj else 0) assert len(evoked.info['bads']) == 2 rank = 17 if proj else 20 assert 'LCMV' in repr(filters) assert 'unknown subject' not in repr(filters) assert '4157 vert' in repr(filters) assert '20 ch' in repr(filters) assert 'rank %s' % rank in repr(filters) # I/O fname = op.join(str(tmpdir), 'filters.h5') with pytest.warns(RuntimeWarning, match='-lcmv.h5'): filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) # deal with object_diff strictness filters_read['rank'] = int(filters_read['rank']) filters['rank'] = int(filters['rank']) assert object_diff(filters, filters_read) == '' # Test if fixed forward operator is detected when picking normal or # max-power orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') # Test if non-surface oriented forward operator is detected when picking # normal orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if volume forward operator is detected when picking normal # orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if missing of noise covariance matrix is detected when more than # one channel type is present in the data pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov=data_cov, reg=0.01, noise_cov=None, pick_ori='max-power') # Test if wrong channel selection is detected in application of filter evoked_ch = deepcopy(evoked) evoked_ch.pick_channels(evoked_ch.ch_names[1:]) filters = make_lcmv(evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) pytest.raises(ValueError, apply_lcmv, evoked_ch, filters, max_ori_out='signed') # Test if discrepancies in channel selection of data and fwd model are # handled correctly in apply_lcmv # make filter with data where first channel was removed filters = make_lcmv(evoked_ch.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) # applying that filter to the full data set should automatically exclude # this channel from the data # also test here that no warnings are thrown - implemented to check whether # src should not be None warning occurs with pytest.warns(None) as w: stc = apply_lcmv(evoked, filters, max_ori_out='signed') assert len(w) == 0 # the result should be equal to applying this filter to a dataset without # this channel: stc_ch = apply_lcmv(evoked_ch, filters, max_ori_out='signed') assert_array_almost_equal(stc.data, stc_ch.data) # Test if non-matching SSP projection is detected in application of filter if proj: raw_proj = deepcopy(raw) raw_proj.del_proj() with pytest.raises(ValueError, match='do not match the projections'): apply_lcmv_raw(raw_proj, filters, max_ori_out='signed') # Test if spatial filter contains src_type assert 'src_type' in filters # check whether a filters object without src_type throws expected warning del filters['src_type'] # emulate 0.16 behaviour to cause warning with pytest.warns(RuntimeWarning, match='spatial filter does not contain ' 'src_type'): apply_lcmv(evoked, filters, max_ori_out='signed') # Now test single trial using fixed orientation forward solution # so we can compare it to the evoked solution filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stcs = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') stcs_ = apply_lcmv_epochs(epochs, filters, return_generator=True, max_ori_out='signed') assert_array_equal(stcs[0].data, next(stcs_).data) epochs.drop_bad() assert (len(epochs.events) == len(stcs)) # average the single trial estimates stc_avg = np.zeros_like(stcs[0].data) for this_stc in stcs: stc_avg += this_stc.data stc_avg /= len(stcs) # compare it to the solution using evoked with fixed orientation filters = make_lcmv(evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stc_fixed = apply_lcmv(evoked, filters, max_ori_out='signed') assert_array_almost_equal(stc_avg, stc_fixed.data) # use a label so we have few source vertices and delayed computation is # not used filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, label=label) stcs_label = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data) # Test condition where the filters weights are zero. There should not be # any divide-by-zero errors zero_cov = data_cov.copy() zero_cov['data'][:] = 0 filters = make_lcmv(epochs.info, forward_fixed, zero_cov, reg=0.01, noise_cov=noise_cov) assert_array_equal(filters['weights'], 0) # Test condition where one channel type is picked # (avoid "grad data rank (13) did not match the noise rank (None)") data_cov_grad = pick_channels_cov( data_cov, [ch_name for ch_name in epochs.info['ch_names'] if ch_name.endswith(('2', '3'))]) assert len(data_cov_grad['names']) > 4 make_lcmv(epochs.info, forward_fixed, data_cov_grad, reg=0.01, noise_cov=noise_cov)
def test_make_dics(tmpdir): """Test making DICS beamformer filters.""" # We only test proper handling of parameters here. Testing the results is # done in test_apply_dics_timeseries and test_apply_dics_csd. fwd_free, fwd_surf, fwd_fixed, fwd_vol, label = _load_forward() epochs, _, csd, _ = _simulate_data(fwd_fixed) raises(ValueError, make_dics, epochs.info, fwd_fixed, csd, pick_ori="notexistent") with raises(ValueError, match='rank, if str'): make_dics(epochs.info, fwd_fixed, csd, rank='foo') with raises(TypeError, match='rank must be'): make_dics(epochs.info, fwd_fixed, csd, rank=1.) # Test if fixed forward operator is detected when picking normal # orientation raises(ValueError, make_dics, epochs.info, fwd_fixed, csd, pick_ori="normal") # Test if non-surface oriented forward operator is detected when picking # normal orientation raises(ValueError, make_dics, epochs.info, fwd_free, csd, pick_ori="normal") # Test if volume forward operator is detected when picking normal # orientation raises(ValueError, make_dics, epochs.info, fwd_vol, csd, pick_ori="normal") # Test invalid combinations of parameters raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd, reduce_rank=True, pick_ori=None) raises(NotImplementedError, make_dics, epochs.info, fwd_free, csd, reduce_rank=True, pick_ori='max-power', inversion='single') # Sanity checks on the returned filters n_freq = len(csd.frequencies) vertices = np.intersect1d(label.vertices, fwd_free['src'][0]['vertno']) n_verts = len(vertices) n_orient = 3 n_channels = csd.n_channels # Test return values filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori=None, weight_norm='unit-noise-gain') assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert np.iscomplexobj(filters['weights']) assert filters['csd'] == csd assert filters['ch_names'] == csd.ch_names assert_array_equal(filters['proj'], np.eye(n_channels)) assert_array_equal(filters['vertices'][0], vertices) assert_array_equal(filters['vertices'][1], []) # Label was on the LH assert filters['subject'] == fwd_free['src'][0]['subject_his_id'] assert filters['pick_ori'] is None assert filters['n_orient'] == n_orient assert filters['inversion'] == 'single' assert filters['normalize_fwd'] assert filters['weight_norm'] == 'unit-noise-gain' assert 'DICS' in repr(filters) assert 'subject "sample"' in repr(filters) assert '13' in repr(filters) assert '62' in repr(filters) assert 'rank' not in repr(filters) _test_weight_norm(filters) # Test picking orientations. Also test weight norming under these different # conditions. filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', weight_norm='unit-noise-gain') n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert filters['n_orient'] == n_orient _test_weight_norm(filters) filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='max-power', weight_norm='unit-noise-gain') n_orient = 1 assert filters['weights'].shape == (n_freq, n_verts * n_orient, n_channels) assert filters['n_orient'] == n_orient _test_weight_norm(filters) # From here on, only work on a single frequency csd = csd[0] # Test using a real-valued filter filters = make_dics(epochs.info, fwd_surf, csd, label=label, pick_ori='normal', real_filter=True) assert not np.iscomplexobj(filters['weights']) # Test forward normalization. When inversion='single', the power of a # unit-noise CSD should be 1, even without weight normalization. csd_noise = csd.copy() inds = np.triu_indices(csd.n_channels) # Using [:, :] syntax for in-place broadcasting csd_noise._data[:, :] = np.eye(csd.n_channels)[inds][:, np.newaxis] filters = make_dics(epochs.info, fwd_surf, csd_noise, label=label, weight_norm=None, normalize_fwd=True) w = filters['weights'][0][:3] assert_allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-6, atol=0) # Test turning off both forward and weight normalization filters = make_dics(epochs.info, fwd_surf, csd, label=label, weight_norm=None, normalize_fwd=False) w = filters['weights'][0][:3] assert not np.allclose(np.diag(w.dot(w.T)), 1.0, rtol=1e-2, atol=0) # Test neural-activity-index weight normalization. It should be a scaled # version of the unit-noise-gain beamformer. filters_nai = make_dics(epochs.info, fwd_surf, csd, label=label, weight_norm='nai', normalize_fwd=False) w_nai = filters_nai['weights'][0] filters_ung = make_dics(epochs.info, fwd_surf, csd, label=label, weight_norm='unit-noise-gain', normalize_fwd=False) w_ung = filters_ung['weights'][0] assert np.allclose(np.corrcoef(np.abs(w_nai).ravel(), np.abs(w_ung).ravel()), 1) # Test whether spatial filter contains src_type assert 'src_type' in filters fname = op.join(str(tmpdir), 'filters-dics.h5') filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) for key in ['tmin', 'tmax']: # deal with strictness of object_diff setattr(filters['csd'], key, np.float(getattr(filters['csd'], key))) assert object_diff(filters, filters_read) == ''
def test_make_lcmv(tmpdir): """Test LCMV with evoked data and single trials.""" raw, epochs, evoked, data_cov, noise_cov, label, forward,\ forward_surf_ori, forward_fixed, forward_vol = _get_data() for fwd in [forward, forward_vol]: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov) stc = apply_lcmv(evoked, filters, max_ori_out='signed') stc.crop(0.02, None) stc_pow = np.sum(np.abs(stc.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc.data[idx] tmax = stc.times[np.argmax(max_stc)] assert 0.09 < tmax < 0.12, tmax assert 0.9 < np.max(max_stc) < 3., np.max(max_stc) if fwd is forward: # Test picking normal orientation (surface source space only) filters = make_lcmv(evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal', weight_norm=None) stc_normal = apply_lcmv(evoked, filters, max_ori_out='signed') stc_normal.crop(0.02, None) stc_pow = np.sum(np.abs(stc_normal.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc_normal.data[idx] tmax = stc_normal.times[np.argmax(max_stc)] assert 0.04 < tmax < 0.13, tmax assert 3e-7 < np.max(max_stc) < 5e-7, np.max(max_stc) # The amplitude of normal orientation results should always be # smaller than free orientation results assert (np.abs(stc_normal.data) <= stc.data).all() # Test picking source orientation maximizing output source power filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') stc_max_power = apply_lcmv(evoked, filters, max_ori_out='signed') stc_max_power.crop(0.02, None) stc_pow = np.sum(np.abs(stc_max_power.data), axis=1) idx = np.argmax(stc_pow) max_stc = np.abs(stc_max_power.data[idx]) tmax = stc.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.12, tmax assert 0.8 < np.max(max_stc) < 3., np.max(max_stc) stc_max_power.data[:, :] = np.abs(stc_max_power.data) if fwd is forward: # Maximum output source power orientation results should be # similar to free orientation results in areas with channel # coverage label = mne.read_label(fname_label) mean_stc = stc.extract_label_time_course(label, fwd['src'], mode='mean') mean_stc_max_pow = \ stc_max_power.extract_label_time_course(label, fwd['src'], mode='mean') assert_array_less(np.abs(mean_stc - mean_stc_max_pow), 0.6) # Test NAI weight normalization: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai') stc_nai = apply_lcmv(evoked, filters, max_ori_out='signed') stc_nai.crop(0.02, None) # Test whether unit-noise-gain solution is a scaled version of NAI pearsoncorr = np.corrcoef(np.concatenate(np.abs(stc_nai.data)), np.concatenate(stc_max_power.data)) assert_almost_equal(pearsoncorr[0, 1], 1.) # Test sphere head model with unit-noise gain beamformer and orientation # selection and rank reduction of the leadfield sphere = mne.make_sphere_model(r0=(0., 0., 0.), head_radius=0.080) src = mne.setup_volume_source_space(subject=None, pos=15., mri=None, sphere=(0.0, 0.0, 0.0, 80.0), bem=None, mindist=5.0, exclude=2.0) fwd_sphere = mne.make_forward_solution(evoked.info, trans=None, src=src, bem=sphere, eeg=False, meg=True) # Test that we get an error if not reducing rank pytest.raises(ValueError, make_lcmv, evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=False) # Now let's reduce it filters = make_lcmv(evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=True) stc_sphere = apply_lcmv(evoked, filters, max_ori_out='signed') stc_sphere = np.abs(stc_sphere) stc_sphere.crop(0.02, None) stc_pow = np.sum(stc_sphere.data, axis=1) idx = np.argmax(stc_pow) max_stc = stc_sphere.data[idx] tmax = stc_sphere.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.15, tmax assert 0.4 < np.max(max_stc) < 2., np.max(max_stc) # Test if spatial filter contains src_type assert 'src_type' in filters # __repr__ assert 'LCMV' in repr(filters) assert 'unknown subject' not in repr(filters) assert '484' in repr(filters) assert '20' in repr(filters) assert 'rank 17' in repr(filters) # I/O fname = op.join(str(tmpdir), 'filters.h5') with pytest.warns(RuntimeWarning, match='-lcmv.h5'): filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) # deal with object_diff strictness filters_read['rank'] = int(filters_read['rank']) filters['rank'] = int(filters['rank']) assert object_diff(filters, filters_read) == '' # Test if fixed forward operator is detected when picking normal or # max-power orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') # Test if non-surface oriented forward operator is detected when picking # normal orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if volume forward operator is detected when picking normal # orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if missing of noise covariance matrix is detected when more than # one channel type is present in the data pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov=data_cov, reg=0.01, noise_cov=None, pick_ori='max-power') # Test if not-yet-implemented orientation selections raise error with # neural activity index pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai') pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori=None, weight_norm='nai') # Test if no weight-normalization and max-power source orientation throws # an error pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm=None) # Test if wrong channel selection is detected in application of filter evoked_ch = deepcopy(evoked) evoked_ch.pick_channels(evoked_ch.ch_names[1:]) filters = make_lcmv(evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) pytest.raises(ValueError, apply_lcmv, evoked_ch, filters, max_ori_out='signed') # Test if discrepancies in channel selection of data and fwd model are # handled correctly in apply_lcmv # make filter with data where first channel was removed filters = make_lcmv(evoked_ch.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) # applying that filter to the full data set should automatically exclude # this channel from the data # also test here that no warnings are thrown - implemented to check whether # src should not be None warning occurs with pytest.warns(None) as w: stc = apply_lcmv(evoked, filters, max_ori_out='signed') assert len(w) == 0 # the result should be equal to applying this filter to a dataset without # this channel: stc_ch = apply_lcmv(evoked_ch, filters, max_ori_out='signed') assert_array_almost_equal(stc.data, stc_ch.data) # Test if non-matching SSP projection is detected in application of filter raw_proj = deepcopy(raw) raw_proj.del_proj() pytest.raises(ValueError, apply_lcmv_raw, raw_proj, filters, max_ori_out='signed') # Test if setting reduce_rank to True returns a NotImplementedError # when no orientation selection is done or pick_ori='normal' pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, noise_cov=noise_cov, pick_ori=None, weight_norm='nai', reduce_rank=True) pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai', reduce_rank=True) # Test if spatial filter contains src_type assert 'src_type' in filters # check whether a filters object without src_type throws expected warning del filters['src_type'] # emulate 0.16 behaviour to cause warning with pytest.warns(RuntimeWarning, match='spatial filter does not contain ' 'src_type'): apply_lcmv(evoked, filters, max_ori_out='signed') # Now test single trial using fixed orientation forward solution # so we can compare it to the evoked solution filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stcs = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') stcs_ = apply_lcmv_epochs(epochs, filters, return_generator=True, max_ori_out='signed') assert_array_equal(stcs[0].data, advance_iterator(stcs_).data) epochs.drop_bad() assert (len(epochs.events) == len(stcs)) # average the single trial estimates stc_avg = np.zeros_like(stcs[0].data) for this_stc in stcs: stc_avg += this_stc.data stc_avg /= len(stcs) # compare it to the solution using evoked with fixed orientation filters = make_lcmv(evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stc_fixed = apply_lcmv(evoked, filters, max_ori_out='signed') assert_array_almost_equal(stc_avg, stc_fixed.data) # use a label so we have few source vertices and delayed computation is # not used filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, label=label) stcs_label = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data) # Test condition where the filters weights are zero. There should not be # any divide-by-zero errors zero_cov = data_cov.copy() zero_cov['data'][:] = 0 filters = make_lcmv(epochs.info, forward_fixed, zero_cov, reg=0.01, noise_cov=noise_cov) assert_array_equal(filters['weights'], 0)
def test_make_lcmv(tmpdir): """Test LCMV with evoked data and single trials.""" raw, epochs, evoked, data_cov, noise_cov, label, forward,\ forward_surf_ori, forward_fixed, forward_vol = _get_data() for fwd in [forward, forward_vol]: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov) stc = apply_lcmv(evoked, filters, max_ori_out='signed') stc.crop(0.02, None) stc_pow = np.sum(np.abs(stc.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc.data[idx] tmax = stc.times[np.argmax(max_stc)] assert 0.09 < tmax < 0.12, tmax assert 0.9 < np.max(max_stc) < 3., np.max(max_stc) if fwd is forward: # Test picking normal orientation (surface source space only). filters = make_lcmv(evoked.info, forward_surf_ori, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal', weight_norm=None) stc_normal = apply_lcmv(evoked, filters, max_ori_out='signed') stc_normal.crop(0.02, None) stc_pow = np.sum(np.abs(stc_normal.data), axis=1) idx = np.argmax(stc_pow) max_stc = stc_normal.data[idx] tmax = stc_normal.times[np.argmax(max_stc)] assert 0.04 < tmax < 0.13, tmax assert 3e-7 < np.max(max_stc) < 5e-7, np.max(max_stc) # No weight normalization was applied, so the amplitude of normal # orientation results should always be smaller than free # orientation results. assert (np.abs(stc_normal.data) <= stc.data).all() # Test picking source orientation maximizing output source power filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') stc_max_power = apply_lcmv(evoked, filters, max_ori_out='signed') stc_max_power.crop(0.02, None) stc_pow = np.sum(np.abs(stc_max_power.data), axis=1) idx = np.argmax(stc_pow) max_stc = np.abs(stc_max_power.data[idx]) tmax = stc.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.12, tmax assert 0.8 < np.max(max_stc) < 3., np.max(max_stc) stc_max_power.data[:, :] = np.abs(stc_max_power.data) if fwd is forward: # Maximum output source power orientation results should be # similar to free orientation results in areas with channel # coverage label = mne.read_label(fname_label) mean_stc = stc.extract_label_time_course(label, fwd['src'], mode='mean') mean_stc_max_pow = \ stc_max_power.extract_label_time_course(label, fwd['src'], mode='mean') assert_array_less(np.abs(mean_stc - mean_stc_max_pow), 0.6) # Test NAI weight normalization: filters = make_lcmv(evoked.info, fwd, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power', weight_norm='nai') stc_nai = apply_lcmv(evoked, filters, max_ori_out='signed') stc_nai.crop(0.02, None) # Test whether unit-noise-gain solution is a scaled version of NAI pearsoncorr = np.corrcoef(np.concatenate(np.abs(stc_nai.data)), np.concatenate(stc_max_power.data)) assert_almost_equal(pearsoncorr[0, 1], 1.) # Test sphere head model with unit-noise gain beamformer and orientation # selection and rank reduction of the leadfield sphere = mne.make_sphere_model(r0=(0., 0., 0.), head_radius=0.080) src = mne.setup_volume_source_space(subject=None, pos=15., mri=None, sphere=(0.0, 0.0, 0.0, 80.0), bem=None, mindist=5.0, exclude=2.0) fwd_sphere = mne.make_forward_solution(evoked.info, trans=None, src=src, bem=sphere, eeg=False, meg=True) # Test that we get an error if not reducing rank with pytest.raises(ValueError): # Singular matrix or complex spectrum make_lcmv( evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=False, rank='full') # Now let's reduce it filters = make_lcmv(evoked.info, fwd_sphere, data_cov, reg=0.1, noise_cov=noise_cov, weight_norm='unit-noise-gain', pick_ori='max-power', reduce_rank=True) stc_sphere = apply_lcmv(evoked, filters, max_ori_out='signed') stc_sphere = np.abs(stc_sphere) stc_sphere.crop(0.02, None) stc_pow = np.sum(stc_sphere.data, axis=1) idx = np.argmax(stc_pow) max_stc = stc_sphere.data[idx] tmax = stc_sphere.times[np.argmax(max_stc)] assert 0.08 < tmax < 0.15, tmax assert 0.4 < np.max(max_stc) < 2., np.max(max_stc) # Test if spatial filter contains src_type assert 'src_type' in filters # __repr__ assert 'LCMV' in repr(filters) assert 'unknown subject' not in repr(filters) assert '484' in repr(filters) assert '20' in repr(filters) assert 'rank 17' in repr(filters) # I/O fname = op.join(str(tmpdir), 'filters.h5') with pytest.warns(RuntimeWarning, match='-lcmv.h5'): filters.save(fname) filters_read = read_beamformer(fname) assert isinstance(filters, Beamformer) assert isinstance(filters_read, Beamformer) # deal with object_diff strictness filters_read['rank'] = int(filters_read['rank']) filters['rank'] = int(filters['rank']) assert object_diff(filters, filters_read) == '' # Test if fixed forward operator is detected when picking normal or # max-power orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') pytest.raises(ValueError, make_lcmv, evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='max-power') # Test if non-surface oriented forward operator is detected when picking # normal orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if volume forward operator is detected when picking normal # orientation pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov, pick_ori='normal') # Test if missing of noise covariance matrix is detected when more than # one channel type is present in the data pytest.raises(ValueError, make_lcmv, evoked.info, forward_vol, data_cov=data_cov, reg=0.01, noise_cov=None, pick_ori='max-power') # Test if wrong channel selection is detected in application of filter evoked_ch = deepcopy(evoked) evoked_ch.pick_channels(evoked_ch.ch_names[1:]) filters = make_lcmv(evoked.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) pytest.raises(ValueError, apply_lcmv, evoked_ch, filters, max_ori_out='signed') # Test if discrepancies in channel selection of data and fwd model are # handled correctly in apply_lcmv # make filter with data where first channel was removed filters = make_lcmv(evoked_ch.info, forward_vol, data_cov, reg=0.01, noise_cov=noise_cov) # applying that filter to the full data set should automatically exclude # this channel from the data # also test here that no warnings are thrown - implemented to check whether # src should not be None warning occurs with pytest.warns(None) as w: stc = apply_lcmv(evoked, filters, max_ori_out='signed') assert len(w) == 0 # the result should be equal to applying this filter to a dataset without # this channel: stc_ch = apply_lcmv(evoked_ch, filters, max_ori_out='signed') assert_array_almost_equal(stc.data, stc_ch.data) # Test if non-matching SSP projection is detected in application of filter raw_proj = deepcopy(raw) raw_proj.del_proj() pytest.raises(ValueError, apply_lcmv_raw, raw_proj, filters, max_ori_out='signed') # Test if setting reduce_rank to True returns a NotImplementedError # when no orientation selection is done or pick_ori='normal' pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_vol, data_cov, noise_cov=noise_cov, pick_ori=None, weight_norm='nai', reduce_rank=True) pytest.raises(NotImplementedError, make_lcmv, evoked.info, forward_surf_ori, data_cov, noise_cov=noise_cov, pick_ori='normal', weight_norm='nai', reduce_rank=True) # Test if spatial filter contains src_type assert 'src_type' in filters # check whether a filters object without src_type throws expected warning del filters['src_type'] # emulate 0.16 behaviour to cause warning with pytest.warns(RuntimeWarning, match='spatial filter does not contain ' 'src_type'): apply_lcmv(evoked, filters, max_ori_out='signed') # Now test single trial using fixed orientation forward solution # so we can compare it to the evoked solution filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stcs = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') stcs_ = apply_lcmv_epochs(epochs, filters, return_generator=True, max_ori_out='signed') assert_array_equal(stcs[0].data, next(stcs_).data) epochs.drop_bad() assert (len(epochs.events) == len(stcs)) # average the single trial estimates stc_avg = np.zeros_like(stcs[0].data) for this_stc in stcs: stc_avg += this_stc.data stc_avg /= len(stcs) # compare it to the solution using evoked with fixed orientation filters = make_lcmv(evoked.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov) stc_fixed = apply_lcmv(evoked, filters, max_ori_out='signed') assert_array_almost_equal(stc_avg, stc_fixed.data) # use a label so we have few source vertices and delayed computation is # not used filters = make_lcmv(epochs.info, forward_fixed, data_cov, reg=0.01, noise_cov=noise_cov, label=label) stcs_label = apply_lcmv_epochs(epochs, filters, max_ori_out='signed') assert_array_almost_equal(stcs_label[0].data, stcs[0].in_label(label).data) # Test condition where the filters weights are zero. There should not be # any divide-by-zero errors zero_cov = data_cov.copy() zero_cov['data'][:] = 0 filters = make_lcmv(epochs.info, forward_fixed, zero_cov, reg=0.01, noise_cov=noise_cov) assert_array_equal(filters['weights'], 0)
import mne import numpy as np import matplotlib.pyplot as plt from mne.beamformer import read_beamformer, apply_dics_csd from mne.io.pick import pick_channels_forward, pick_info, pick_channels from mne.time_frequency import CrossSpectralDensity as CSD, csd_morlet from mne.time_frequency.csd import _sym_mat_to_vector plt.ion() proc_dir = "/home/jeff/hdd/cora/leakage/" band = "alpha" filters = read_beamformer("{}nc_NEM_36_limb_mix_{}-dics.h5".format( proc_dir, band)) fwd = mne.read_forward_solution( "{}nc_NEM_36_limb_mix_exp-fwd.fif".format(proc_dir)) epo = mne.read_epochs("{}nc_NEM_36_exp-epo.fif".format(proc_dir)) info = epo.info # get leadfield from forward, using only good channels ch_names = [c for c in filters["ch_names"] if (c not in info["bads"])] fwd = pick_channels_forward(fwd, ch_names, ordered=True) leadfield = fwd['sol']['data'] # get inverse matrix from DICS filter invmat = np.abs(filters["weights"][0]) # resolution matrix resmat = invmat.dot(leadfield)