def test_make_inverse_operator_free(evoked, noise_cov): """Test MNE inverse computation (free orientation).""" fwd = read_forward_solution_meg(fname_fwd) fwd_surf = convert_forward_solution(fwd, surf_ori=True) fwd_fixed = convert_forward_solution(fwd, force_fixed=True, use_cps=True) # can't make free inv with fixed fwd with pytest.raises(ValueError, match='can only be used'): make_inverse_operator(evoked.info, fwd_fixed, noise_cov, depth=None) # for depth=None (or depth=0.8), surf_ori of the fwd should not matter inv_surf = make_inverse_operator(evoked.info, fwd_surf, noise_cov, depth=None, loose=1.) inv = make_inverse_operator(evoked.info, fwd, noise_cov, depth=None, loose=1.) _compare_inverses_approx(inv, inv_surf, evoked, rtol=1e-5, atol=1e-8, check_nn=False, check_K=False) for pick_ori in (None, 'vector', 'normal'): stc = apply_inverse(evoked, inv, pick_ori=pick_ori) stc_surf = apply_inverse(evoked, inv_surf, pick_ori=pick_ori) assert_allclose(stc_surf.data, stc.data, atol=1e-2)
def _compare_inverses_approx(inv_1, inv_2, evoked, stc_decimals, check_depth=True): if check_depth: if inv_1['depth_prior'] is not None: assert_array_almost_equal(inv_1['depth_prior']['data'], inv_2['depth_prior']['data']) else: assert_true(inv_2['depth_prior'] is None) if inv_1['orient_prior'] is not None: assert_array_almost_equal(inv_1['orient_prior']['data'], inv_2['orient_prior']['data']) else: assert_true(inv_2['orient_prior'] is None) assert_array_almost_equal(inv_1['source_cov']['data'], inv_2['source_cov']['data']) # These are not as close as we'd like XXX assert_array_almost_equal(np.abs(inv_1['eigen_fields']['data']), np.abs(inv_2['eigen_fields']['data']), 0) assert_array_almost_equal(np.abs(inv_1['eigen_leads']['data']), np.abs(inv_2['eigen_leads']['data']), 0) stc_1 = apply_inverse(evoked, inv_1, lambda2, "dSPM") stc_2 = apply_inverse(evoked, inv_2, lambda2, "dSPM") assert_equal(stc_1.times, stc_2.times) assert_array_almost_equal(stc_1.data, stc_2.data, stc_decimals)
def _compare_inverses_approx(inv_1, inv_2, evoked, rtol, atol, check_depth=True): # depth prior if check_depth: if inv_1['depth_prior'] is not None: assert_array_almost_equal(inv_1['depth_prior']['data'], inv_2['depth_prior']['data'], 5) else: assert_true(inv_2['depth_prior'] is None) # orient prior if inv_1['orient_prior'] is not None: assert_array_almost_equal(inv_1['orient_prior']['data'], inv_2['orient_prior']['data']) else: assert_true(inv_2['orient_prior'] is None) # source cov assert_array_almost_equal(inv_1['source_cov']['data'], inv_2['source_cov']['data']) # These are not as close as we'd like XXX assert_array_almost_equal(np.abs(inv_1['eigen_fields']['data']), np.abs(inv_2['eigen_fields']['data']), 0) assert_array_almost_equal(np.abs(inv_1['eigen_leads']['data']), np.abs(inv_2['eigen_leads']['data']), 0) stc_1 = apply_inverse(evoked, inv_1, lambda2, "dSPM") stc_2 = apply_inverse(evoked, inv_2, lambda2, "dSPM") assert_true(stc_1.subject == stc_2.subject) assert_equal(stc_1.times, stc_2.times) assert_allclose(stc_1.data, stc_2.data, rtol=rtol, atol=atol) assert_true(inv_1['units'] == inv_2['units'])
def _compare_inverses_approx(inv_1, inv_2, evoked, stc_decimals, check_depth=True): # depth prior if check_depth: if inv_1['depth_prior'] is not None: assert_array_almost_equal(inv_1['depth_prior']['data'], inv_2['depth_prior']['data']) else: assert_true(inv_2['depth_prior'] is None) # orient prior if inv_1['orient_prior'] is not None: assert_array_almost_equal(inv_1['orient_prior']['data'], inv_2['orient_prior']['data']) else: assert_true(inv_2['orient_prior'] is None) # source cov assert_array_almost_equal(inv_1['source_cov']['data'], inv_2['source_cov']['data']) # These are not as close as we'd like XXX assert_array_almost_equal(np.abs(inv_1['eigen_fields']['data']), np.abs(inv_2['eigen_fields']['data']), 0) assert_array_almost_equal(np.abs(inv_1['eigen_leads']['data']), np.abs(inv_2['eigen_leads']['data']), 0) stc_1 = apply_inverse(evoked, inv_1, lambda2, "dSPM") stc_2 = apply_inverse(evoked, inv_2, lambda2, "dSPM") assert_true(stc_1.subject == stc_2.subject) assert_equal(stc_1.times, stc_2.times) assert_array_almost_equal(stc_1.data, stc_2.data, stc_decimals) assert_true(inv_1['units'] == inv_2['units'])
def test_make_inverse_operator_fixed(): """Test MNE inverse computation with fixed orientation""" # XXX : should be fixed and not skipped raise nose.SkipTest("XFailed Test") evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0)) fwd_op = read_forward_solution(fname_fwd, force_fixed=True) inv_op = make_inverse_operator(evoked.info, fwd_op, noise_cov, depth=0.8, loose=None) assert_array_almost_equal(inverse_operator_fixed['depth_prior']['data'], inv_op['depth_prior']['data']) assert_equal(inverse_operator_fixed['orient_prior'], inv_op['orient_prior']) assert_array_almost_equal(inverse_operator_fixed['source_cov']['data'], inv_op['source_cov']['data']) stc_fixed = apply_inverse(evoked, inverse_operator_fixed, lambda2, "dSPM") my_stc = apply_inverse(evoked, inv_op, lambda2, "dSPM") assert_equal(stc_fixed.times, my_stc.times) assert_array_almost_equal(stc_fixed.data, my_stc.data, 2)
def _compare_inverses_approx(inv_1, inv_2, evoked, rtol, atol, depth_atol=1e-6, ctol=0.999999, check_nn=True, check_K=True): """Compare inverses.""" # depth prior if inv_1['depth_prior'] is not None: assert_allclose(inv_1['depth_prior']['data'], inv_2['depth_prior']['data'], atol=depth_atol) else: assert_true(inv_2['depth_prior'] is None) # orient prior if inv_1['orient_prior'] is not None: assert_allclose(inv_1['orient_prior']['data'], inv_2['orient_prior']['data'], atol=1e-7) else: assert_true(inv_2['orient_prior'] is None) # source cov assert_allclose(inv_1['source_cov']['data'], inv_2['source_cov']['data'], atol=1e-7) for key in ('units', 'eigen_leads_weighted', 'nsource', 'coord_frame'): assert_equal(inv_1[key], inv_2[key], err_msg=key) assert_equal(inv_1['eigen_leads']['ncol'], inv_2['eigen_leads']['ncol']) K_1 = np.dot(inv_1['eigen_leads']['data'] * inv_1['sing'].astype(float), inv_1['eigen_fields']['data']) K_2 = np.dot(inv_2['eigen_leads']['data'] * inv_2['sing'].astype(float), inv_2['eigen_fields']['data']) # for free + surf ori, we only care about the ::2 # (the other two dimensions have arbitrary direction) if inv_1['nsource'] * 3 == inv_1['source_nn'].shape[0]: # Technically this undersamples the free-orientation, non-surf-ori # inverse, but it's probably okay sl = slice(2, None, 3) else: sl = slice(None) if check_nn: assert_allclose(inv_1['source_nn'][sl], inv_2['source_nn'][sl], atol=1e-4) if check_K: assert_allclose(np.abs(K_1[sl]), np.abs(K_2[sl]), rtol=rtol, atol=atol) # Now let's do some practical tests, too evoked = EvokedArray(np.eye(len(evoked.ch_names)), evoked.info) for method in ('MNE', 'dSPM'): stc_1 = apply_inverse(evoked, inv_1, lambda2, method) stc_2 = apply_inverse(evoked, inv_2, lambda2, method) assert_equal(stc_1.subject, stc_2.subject) assert_equal(stc_1.times, stc_2.times) stc_1 = stc_1.data stc_2 = stc_2.data norms = np.max(stc_1, axis=-1, keepdims=True) stc_1 /= norms stc_2 /= norms corr = np.corrcoef(stc_1.ravel(), stc_2.ravel())[0, 1] assert_true(corr > ctol, msg='%s < %s' % (corr, ctol)) assert_allclose(stc_1, stc_2, rtol=rtol, atol=atol, err_msg='%s: %s' % (method, corr))
def _compare_inverses_approx(inv_1, inv_2, evoked, rtol, atol, depth_atol=1e-6, ctol=0.999999, check_nn=True, check_K=True): """Compare inverses.""" # depth prior if inv_1['depth_prior'] is not None: assert_allclose(inv_1['depth_prior']['data'], inv_2['depth_prior']['data'], atol=depth_atol) else: assert (inv_2['depth_prior'] is None) # orient prior if inv_1['orient_prior'] is not None: assert_allclose(inv_1['orient_prior']['data'], inv_2['orient_prior']['data'], atol=1e-7) else: assert (inv_2['orient_prior'] is None) # source cov assert_allclose(inv_1['source_cov']['data'], inv_2['source_cov']['data'], atol=1e-7) for key in ('units', 'eigen_leads_weighted', 'nsource', 'coord_frame'): assert_equal(inv_1[key], inv_2[key], err_msg=key) assert_equal(inv_1['eigen_leads']['ncol'], inv_2['eigen_leads']['ncol']) K_1 = np.dot(inv_1['eigen_leads']['data'] * inv_1['sing'].astype(float), inv_1['eigen_fields']['data']) K_2 = np.dot(inv_2['eigen_leads']['data'] * inv_2['sing'].astype(float), inv_2['eigen_fields']['data']) # for free + surf ori, we only care about the ::2 # (the other two dimensions have arbitrary direction) if inv_1['nsource'] * 3 == inv_1['source_nn'].shape[0]: # Technically this undersamples the free-orientation, non-surf-ori # inverse, but it's probably okay sl = slice(2, None, 3) else: sl = slice(None) if check_nn: assert_allclose(inv_1['source_nn'][sl], inv_2['source_nn'][sl], atol=1e-4) if check_K: assert_allclose(np.abs(K_1[sl]), np.abs(K_2[sl]), rtol=rtol, atol=atol) # Now let's do some practical tests, too evoked = EvokedArray(np.eye(len(evoked.ch_names)), evoked.info) for method in ('MNE', 'dSPM'): stc_1 = apply_inverse(evoked, inv_1, lambda2, method) stc_2 = apply_inverse(evoked, inv_2, lambda2, method) assert_equal(stc_1.subject, stc_2.subject) assert_equal(stc_1.times, stc_2.times) stc_1 = stc_1.data stc_2 = stc_2.data norms = np.max(stc_1, axis=-1, keepdims=True) stc_1 /= norms stc_2 /= norms corr = np.corrcoef(stc_1.ravel(), stc_2.ravel())[0, 1] assert corr > ctol assert_allclose(stc_1, stc_2, rtol=rtol, atol=atol, err_msg='%s: %s' % (method, corr))
def test_apply_inverse_operator(): """Test MNE inverse computation (precomputed and non-precomputed) """ inverse_operator = read_inverse_operator(fname_inv) evoked = _get_evoked() noise_cov = read_cov(fname_cov) # Test old version of inverse computation starting from forward operator fwd_op = read_forward_solution(fname_fwd, surf_ori=True) my_inv_op = make_inverse_operator(evoked.info, fwd_op, noise_cov, loose=0.2, depth=0.8, limit_depth_chs=False) _compare_io(my_inv_op) assert_true(inverse_operator['units'] == 'Am') _compare_inverses_approx(my_inv_op, inverse_operator, evoked, 2, check_depth=False) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) # Test MNE inverse computation starting from forward operator my_inv_op = make_inverse_operator(evoked.info, fwd_op, noise_cov, loose=0.2, depth=0.8) _compare_io(my_inv_op) _compare_inverses_approx(my_inv_op, inverse_operator, evoked, 2) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-10) assert_true(stc.data.mean() > 1e-11) stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1) my_stc = apply_inverse(evoked, my_inv_op, lambda2, "dSPM") assert_true('dev_head_t' in my_inv_op['info']) assert_true('mri_head_t' in my_inv_op) assert_true(my_stc.subject == 'sample') assert_equal(stc.times, my_stc.times) assert_array_almost_equal(stc.data, my_stc.data, 2)
def test_inverse_operator_channel_ordering(): """Test MNE inverse computation is immune to channel reorderings """ # These are with original ordering evoked = _get_evoked() noise_cov = read_cov(fname_cov) fwd_orig = make_forward_solution(evoked.info, fname_trans, src_fname, fname_bem, eeg=True, mindist=5.0) fwd_orig = convert_forward_solution(fwd_orig, surf_ori=True) inv_orig = make_inverse_operator(evoked.info, fwd_orig, noise_cov, loose=0.2, depth=0.8, limit_depth_chs=False) stc_1 = apply_inverse(evoked, inv_orig, lambda2, "dSPM") # Assume that a raw reordering applies to both evoked and noise_cov, # so we don't need to create those from scratch. Just reorder them, # then try to apply the original inverse operator new_order = np.arange(len(evoked.info['ch_names'])) randomiser = np.random.RandomState(42) randomiser.shuffle(new_order) evoked.data = evoked.data[new_order] evoked.info['chs'] = [evoked.info['chs'][n] for n in new_order] evoked.info._update_redundant() evoked.info._check_consistency() cov_ch_reorder = [c for c in evoked.info['ch_names'] if (c in noise_cov.ch_names)] new_order_cov = [noise_cov.ch_names.index(name) for name in cov_ch_reorder] noise_cov['data'] = noise_cov.data[np.ix_(new_order_cov, new_order_cov)] noise_cov['names'] = [noise_cov['names'][idx] for idx in new_order_cov] fwd_reorder = make_forward_solution(evoked.info, fname_trans, src_fname, fname_bem, eeg=True, mindist=5.0) fwd_reorder = convert_forward_solution(fwd_reorder, surf_ori=True) inv_reorder = make_inverse_operator(evoked.info, fwd_reorder, noise_cov, loose=0.2, depth=0.8, limit_depth_chs=False) stc_2 = apply_inverse(evoked, inv_reorder, lambda2, "dSPM") assert_equal(stc_1.subject, stc_2.subject) assert_array_equal(stc_1.times, stc_2.times) assert_allclose(stc_1.data, stc_2.data, rtol=1e-5, atol=1e-5) assert_true(inv_orig['units'] == inv_reorder['units']) # Reload with original ordering & apply reordered inverse evoked = _get_evoked() noise_cov = read_cov(fname_cov) stc_3 = apply_inverse(evoked, inv_reorder, lambda2, "dSPM") assert_allclose(stc_1.data, stc_3.data, rtol=1e-5, atol=1e-5)
def test_apply_inverse_sphere(evoked): """Test applying an inverse with a sphere model (rank-deficient).""" evoked.pick_channels(evoked.ch_names[:306:8]) evoked.info['projs'] = [] cov = make_ad_hoc_cov(evoked.info) sphere = make_sphere_model('auto', 'auto', evoked.info) fwd = read_forward_solution(fname_fwd) vertices = [fwd['src'][0]['vertno'][::5], fwd['src'][1]['vertno'][::5]] stc = SourceEstimate(np.zeros((sum(len(v) for v in vertices), 1)), vertices, 0., 1.) fwd = restrict_forward_to_stc(fwd, stc) fwd = make_forward_solution(evoked.info, fwd['mri_head_t'], fwd['src'], sphere, mindist=5.) evoked = EvokedArray(fwd['sol']['data'].copy(), evoked.info) assert fwd['sol']['nrow'] == 39 assert fwd['nsource'] == 101 assert fwd['sol']['ncol'] == 303 tempdir = _TempDir() temp_fname = op.join(tempdir, 'temp-inv.fif') inv = make_inverse_operator(evoked.info, fwd, cov, loose=1.) # This forces everything to be float32 write_inverse_operator(temp_fname, inv) inv = read_inverse_operator(temp_fname) stc = apply_inverse(evoked, inv, method='eLORETA', method_params=dict(eps=1e-2)) # assert zero localization bias assert_array_equal(np.argmax(stc.data, axis=0), np.repeat(np.arange(101), 3))
def test_apply_inverse_sphere(): """Test applying an inverse with a sphere model (rank-deficient).""" evoked = _get_evoked() evoked.pick_channels(evoked.ch_names[:306:8]) evoked.info['projs'] = [] cov = make_ad_hoc_cov(evoked.info) sphere = make_sphere_model('auto', 'auto', evoked.info) fwd = read_forward_solution(fname_fwd) vertices = [fwd['src'][0]['vertno'][::5], fwd['src'][1]['vertno'][::5]] stc = SourceEstimate(np.zeros((sum(len(v) for v in vertices), 1)), vertices, 0., 1.) fwd = restrict_forward_to_stc(fwd, stc) fwd = make_forward_solution(evoked.info, fwd['mri_head_t'], fwd['src'], sphere, mindist=5.) evoked = EvokedArray(fwd['sol']['data'].copy(), evoked.info) assert fwd['sol']['nrow'] == 39 assert fwd['nsource'] == 101 assert fwd['sol']['ncol'] == 303 tempdir = _TempDir() temp_fname = op.join(tempdir, 'temp-inv.fif') inv = make_inverse_operator(evoked.info, fwd, cov, loose=1.) # This forces everything to be float32 write_inverse_operator(temp_fname, inv) inv = read_inverse_operator(temp_fname) stc = apply_inverse(evoked, inv, method='eLORETA', method_params=dict(eps=1e-2)) # assert zero localization bias assert_array_equal(np.argmax(stc.data, axis=0), np.repeat(np.arange(101), 3))
def test_inverse_residual(evoked): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = evoked.pick_types() inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) pick_channels_forward(fwd, evoked.ch_names, copy=False) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') for method in ('MNE', 'dSPM', 'sLORETA'): with catch_logging() as log: stc, residual = apply_inverse(evoked, inv, method=method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method == 'MNE': # must be first! recon = apply_forward(fwd, stc, evoked.info) proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 with catch_logging() as log: _, residual = apply_inverse(evoked, inv, 0., 'MNE', return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15) # Degenerate: we don't have the right representation for eLORETA for this with pytest.raises(ValueError, match='eLORETA does not .* support .*'): apply_inverse(evoked, inv, method="eLORETA", return_residual=True)
def test_apply_inverse_operator(): """Test MNE inverse application """ inverse_operator = read_inverse_operator(fname_full) evoked = _get_evoked() # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-9) assert_true(stc.data.mean() > 1e-11) # test if using prepared and not prepared inverse operator give the same # result inv_op = prepare_inverse_operator(inverse_operator, nave=evoked.nave, lambda2=lambda2, method="MNE") stc2 = apply_inverse(evoked, inv_op, lambda2, "MNE") assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1) # Test we get errors when using custom ref or no average proj is present evoked.info['custom_ref_applied'] = True assert_raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") evoked.info['custom_ref_applied'] = False evoked.info['projs'] = [] # remove EEG proj assert_raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE")
def test_apply_inverse_eLORETA_MNE_equiv(bias_params_free, loose, lambda2): """Test that eLORETA with no iterations is the same as MNE.""" method_params = dict(max_iter=0, force_equal=False) pick_ori = None if loose == 0 else 'vector' evoked, fwd, noise_cov, _, _ = bias_params_free inv = make_inverse_operator( evoked.info, fwd, noise_cov, loose=loose, depth=None, verbose='debug') stc_mne = apply_inverse(evoked, inv, lambda2, 'MNE', pick_ori=pick_ori, verbose='debug') with pytest.warns(RuntimeWarning, match='converge'): stc_e = apply_inverse(evoked, inv, lambda2, 'eLORETA', method_params=method_params, pick_ori=pick_ori, verbose='debug') atol = np.mean(np.abs(stc_mne.data)) * 1e-6 assert 3e-9 < atol < 3e-6 # nothing has blown up assert_allclose(stc_mne.data, stc_e.data, atol=atol, rtol=1e-4)
def test_apply_inverse_operator(self): """Test MNE inverse computation (precomputed and non-precomputed) """ # Test old version of inverse computation starting from forward # operator my_inv_op = make_inverse_operator(evoked.info, self.fwd_op, noise_cov, loose=0.2, depth=0.8, limit_depth_chs=False) _compare_io(my_inv_op) _compare_inverses_approx(my_inv_op, self.inv_op, evoked, 2, check_depth=False) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(self.inv_op) == 302) # Test MNE inverse computation starting from forward operator my_inv_op = make_inverse_operator(evoked.info, self.fwd_op, noise_cov, loose=0.2, depth=0.8) _compare_io(my_inv_op) _compare_inverses_approx(my_inv_op, self.inv_op, evoked, 2) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(self.inv_op) == 302) stc = apply_inverse(evoked, self.inv_op, lambda2, "MNE") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-10) assert_true(stc.data.mean() > 1e-11) stc = apply_inverse(evoked, self.inv_op, lambda2, "sLORETA") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 9.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, self.inv_op, lambda2, "dSPM") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1) my_stc = apply_inverse(evoked, my_inv_op, lambda2, "dSPM") assert_true('dev_head_t' in my_inv_op['info']) assert_true('mri_head_t' in my_inv_op) assert_equal(stc.times, my_stc.times) assert_array_almost_equal(stc.data, my_stc.data, 2)
def test_make_inverse_operator_vector(evoked, noise_cov): """Test MNE inverse computation (vector result).""" fwd_surf = read_forward_solution_meg(fname_fwd, surf_ori=True) fwd = read_forward_solution_meg(fname_fwd, surf_ori=False) # Make different version of the inverse operator inv_1 = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1) inv_2 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, depth=None, use_cps=True) inv_3 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, fixed=True, use_cps=True) inv_4 = make_inverse_operator(evoked.info, fwd, noise_cov, loose=.2, depth=None) # Apply the inverse operators and check the result for ii, inv in enumerate((inv_1, inv_2, inv_4)): # Don't do eLORETA here as it will be quite slow methods = ['MNE', 'dSPM', 'sLORETA'] if ii < 2 else ['MNE'] for method in methods: stc = apply_inverse(evoked, inv, method=method) stc_vec = apply_inverse(evoked, inv, pick_ori='vector', method=method) assert_allclose(stc.data, stc_vec.magnitude().data) # Vector estimates don't work when using fixed orientations with pytest.raises(RuntimeError, match='fixed orientation'): apply_inverse(evoked, inv_3, pick_ori='vector') # When computing with vector fields, computing the difference between two # evokeds and then performing the inverse should yield the same result as # computing the difference between the inverses. evoked0 = read_evokeds(fname_data, condition=0, baseline=(None, 0)) evoked0.crop(0, 0.2) evoked1 = read_evokeds(fname_data, condition=1, baseline=(None, 0)) evoked1.crop(0, 0.2) diff = combine_evoked((evoked0, evoked1), [1, -1]) stc_diff = apply_inverse(diff, inv_1, method='MNE') stc_diff_vec = apply_inverse(diff, inv_1, method='MNE', pick_ori='vector') stc_vec0 = apply_inverse(evoked0, inv_1, method='MNE', pick_ori='vector') stc_vec1 = apply_inverse(evoked1, inv_1, method='MNE', pick_ori='vector') assert_allclose(stc_diff_vec.data, (stc_vec0 - stc_vec1).data, atol=1e-20) assert_allclose(stc_diff.data, (stc_vec0 - stc_vec1).magnitude().data, atol=1e-20)
def test_inverse_operator_volume(evoked): """Test MNE inverse computation on volume source space.""" tempdir = _TempDir() inv_vol = read_inverse_operator(fname_vol_inv) assert (repr(inv_vol)) stc = apply_inverse(evoked, inv_vol, lambda2, 'dSPM') assert (isinstance(stc, VolSourceEstimate)) # volume inverses don't have associated subject IDs assert (stc.subject is None) stc.save(op.join(tempdir, 'tmp-vl.stc')) stc2 = read_source_estimate(op.join(tempdir, 'tmp-vl.stc')) assert (np.all(stc.data > 0)) assert (np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) # vector source estimate stc_vec = apply_inverse(evoked, inv_vol, lambda2, 'dSPM', 'vector') assert (repr(stc_vec)) assert_allclose(np.linalg.norm(stc_vec.data, axis=1), stc.data)
def test_apply_inverse_operator(): """Test MNE inverse computation With and without precomputed inverse operator. """ evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0)) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-10) assert_true(stc.data.mean() > 1e-11) stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 9.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1) # Test MNE inverse computation starting from forward operator evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0)) fwd_op = read_forward_solution(fname_fwd, surf_ori=True) my_inv_op = make_inverse_operator(evoked.info, fwd_op, noise_cov, loose=0.2, depth=0.8) write_inverse_operator('test-inv.fif', my_inv_op) read_my_inv_op = read_inverse_operator('test-inv.fif') _compare(my_inv_op, read_my_inv_op) my_stc = apply_inverse(evoked, my_inv_op, lambda2, "dSPM") assert_true('dev_head_t' in my_inv_op['info']) assert_true('mri_head_t' in my_inv_op) assert_equal(stc.times, my_stc.times) assert_array_almost_equal(stc.data, my_stc.data, 2)
def test_inverse_operator_volume(): """Test MNE inverse computation on volume source space""" evoked = fiff.Evoked(fname_data, setno=0, baseline=(None, 0)) inverse_operator_vol = read_inverse_operator(fname_vol_inv) stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM") stc.save('tmp-vl.stc') stc2 = read_source_estimate('tmp-vl.stc') assert_true(np.all(stc.data > 0)) assert_true(np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times)
def test_localization_bias_loose(bias_params_free, method, lower, upper): """Test inverse localization bias for loose minimum-norm solvers.""" evoked, fwd, noise_cov, _, want = bias_params_free inv_free = make_inverse_operator(evoked.info, fwd, noise_cov, loose=0.2, depth=0.8) loc = apply_inverse(evoked, inv_free, lambda2, method, pick_ori='vector').data loc = np.linalg.norm(loc, axis=1) # Compute the percentage of sources for which there is no loc bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method
def test_localization_bias_fixed(bias_params_fixed, method, lower, upper, depth): """Test inverse localization bias for fixed minimum-norm solvers.""" evoked, fwd, noise_cov, _, want = bias_params_fixed fwd_use = convert_forward_solution(fwd, force_fixed=False) inv_fixed = make_inverse_operator(evoked.info, fwd_use, noise_cov, loose=0., depth=depth) loc = np.abs(apply_inverse(evoked, inv_fixed, lambda2, method).data) # Compute the percentage of sources for which there is no loc bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method
def test_localization_bias_free(bias_params_free, method, lower, upper, kwargs, depth): """Test inverse localization bias for free minimum-norm solvers.""" evoked, fwd, noise_cov, _, want = bias_params_free inv_free = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1., depth=depth) loc = apply_inverse(evoked, inv_free, lambda2, method, pick_ori='vector', **kwargs).data loc = np.linalg.norm(loc, axis=1) # Compute the percentage of sources for which there is no loc bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method
def test_inverse_operator_volume(): """Test MNE inverse computation on volume source space """ inverse_operator_vol = read_inverse_operator(fname_vol_inv) _compare_io(inverse_operator_vol) stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM") stc.save(op.join(tempdir, 'tmp-vl.stc')) stc2 = read_source_estimate(op.join(tempdir, 'tmp-vl.stc')) assert_true(np.all(stc.data > 0)) assert_true(np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times)
def test_orientation_prior(bias_params_free, method, looses, vmin, vmax, nmin, nmax): """Test that orientation priors are handled properly.""" evoked, fwd, noise_cov, _, _ = bias_params_free stcs = list() vec_stc = None for loose in looses: inv = make_inverse_operator(evoked.info, fwd, noise_cov, loose=loose) if looses[0] == 0.: pick_ori = None if loose == 0 else 'normal' else: pick_ori = 'vector' stcs.append(apply_inverse( evoked, inv, method=method, pick_ori=pick_ori)) if loose in (1., 0.2): assert vec_stc is None vec_stc = apply_inverse( evoked, inv, method=method, pick_ori='vector') assert vec_stc is not None rot = _normal_orth(np.concatenate( [_get_src_nn(s) for s in inv['src']])) vec_stc_surf = np.matmul(rot, vec_stc.data) if 0. in looses: vec_stc_normal = vec_stc.normal(inv['src']) assert_allclose(stcs[1].data, vec_stc_normal.data) del vec_stc assert_allclose(vec_stc_normal.data, vec_stc_surf[:, 2]) assert_allclose(vec_stc_normal.data, stcs[1].data) # Ensure that our relative strengths are reasonable # (normal should be much larger than tangential) normal = np.linalg.norm(vec_stc_surf[:, 2].ravel()) for ii in range(2): tangential = np.linalg.norm(vec_stc_surf[:, ii].ravel()) ratio = normal / tangential assert nmin < ratio < nmax assert stcs[0].data.shape == stcs[1].data.shape R2 = 1. - ( np.linalg.norm(stcs[0].data.ravel() - stcs[1].data.ravel()) / np.linalg.norm(stcs[0].data.ravel())) assert vmin < R2 < vmax
def test_inverse_residual(): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = _get_evoked().pick_types() inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) fwd = pick_channels_forward(fwd, evoked.ch_names) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') for method in ('MNE', 'dSPM', 'sLORETA'): with catch_logging() as log: stc, residual = apply_inverse( evoked, inv, method=method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method == 'MNE': # must be first! recon = apply_forward(fwd, stc, evoked.info) proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 with catch_logging() as log: _, residual = apply_inverse( evoked, inv, 0., 'MNE', return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15) # Degenerate: we don't have the right representation for eLORETA for this with pytest.raises(ValueError, match='eLORETA does not .* support .*'): apply_inverse(evoked, inv, method="eLORETA", return_residual=True)
def test_apply_inverse_operator(): """Test MNE inverse application """ inverse_operator = read_inverse_operator(fname_full) evoked = _get_evoked() # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-9) assert_true(stc.data.mean() > 1e-11) # test if using prepared and not prepared inverse operator give the same # result inv_op = prepare_inverse_operator(inverse_operator, nave=evoked.nave, lambda2=lambda2, method="MNE") stc2 = apply_inverse(evoked, inv_op, lambda2, "MNE") assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1)
def test_localization_bias_loose(bias_params_fixed, method, lower, upper, depth): """Test inverse localization bias for loose minimum-norm solvers.""" evoked, fwd, noise_cov, _, want = bias_params_fixed fwd = convert_forward_solution(fwd, surf_ori=False, force_fixed=False) assert not is_fixed_orient(fwd) inv_loose = make_inverse_operator(evoked.info, fwd, noise_cov, loose=0.2, depth=depth) loc = apply_inverse(evoked, inv_loose, lambda2, method).data assert (loc >= 0).all() # Compute the percentage of sources for which there is no loc bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method
def test_inverse_residual(evoked, method): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) evoked = evoked.pick_types() inv = read_inverse_operator(fname_inv_fixed_depth) fwd = read_forward_solution(fname_fwd) pick_channels_forward(fwd, evoked.ch_names, copy=False) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) matcher = re.compile(r'.* ([0-9]?[0-9]?[0-9]?\.[0-9])% variance.*') with catch_logging() as log: stc, residual = apply_inverse( evoked, inv, method=method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert 45 < match < 50 if method not in ('dSPM', 'sLORETA'): recon = apply_forward(fwd, stc, evoked.info) proj_op = make_projector(evoked.info['projs'], evoked.ch_names)[0] recon.data[:] = np.dot(proj_op, recon.data) residual_fwd = evoked.copy() residual_fwd.data -= recon.data corr = np.corrcoef(residual_fwd.data.ravel(), residual.data.ravel())[0, 1] assert corr > 0.999 if method != 'sLORETA': # XXX divide by zero error with catch_logging() as log: _, residual = apply_inverse( evoked, inv, 0., method, return_residual=True, verbose=True) log = log.getvalue() match = matcher.match(log.replace('\n', ' ')) assert match is not None match = float(match.group(1)) assert match == 100. assert_array_less(np.abs(residual.data), 1e-15)
def test_inverse_operator_volume(): """Test MNE inverse computation on volume source space """ inverse_operator_vol = read_inverse_operator(fname_vol_inv) _compare_io(inverse_operator_vol) stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM") # volume inverses don't have associated subject IDs assert_true(stc.subject is None) stc.save(op.join(tempdir, 'tmp-vl.stc')) stc2 = read_source_estimate(op.join(tempdir, 'tmp-vl.stc')) assert_true(np.all(stc.data > 0)) assert_true(np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times)
def test_inverse_operator_volume(): """Test MNE inverse computation on volume source space """ evoked = _get_evoked() inverse_operator_vol = read_inverse_operator(fname_vol_inv) _compare_io(inverse_operator_vol) stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM") assert_true(isinstance(stc, VolSourceEstimate)) # volume inverses don't have associated subject IDs assert_true(stc.subject is None) stc.save(op.join(tempdir, 'tmp-vl.stc')) stc2 = read_source_estimate(op.join(tempdir, 'tmp-vl.stc')) assert_true(np.all(stc.data > 0)) assert_true(np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times)
def test_inverse_operator_volume(): """Test MNE inverse computation on volume source space """ tempdir = _TempDir() evoked = _get_evoked() inverse_operator_vol = read_inverse_operator(fname_vol_inv) assert_true(repr(inverse_operator_vol)) stc = apply_inverse(evoked, inverse_operator_vol, lambda2, "dSPM") assert_true(isinstance(stc, VolSourceEstimate)) # volume inverses don't have associated subject IDs assert_true(stc.subject is None) stc.save(op.join(tempdir, 'tmp-vl.stc')) stc2 = read_source_estimate(op.join(tempdir, 'tmp-vl.stc')) assert_true(np.all(stc.data > 0)) assert_true(np.all(stc.data < 35)) assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times)
def test_make_inverse_operator_vector(): """Test MNE inverse computation (vector result).""" fwd_surf = read_forward_solution_meg(fname_fwd, surf_ori=True) fwd_fixed = read_forward_solution_meg(fname_fwd, surf_ori=False) evoked = _get_evoked() noise_cov = read_cov(fname_cov) # Make different version of the inverse operator inv_1 = make_inverse_operator(evoked.info, fwd_fixed, noise_cov, loose=1) inv_2 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, depth=None) inv_3 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, fixed=True, loose=None) # Apply the inverse operators and check the result for inv in [inv_1, inv_2]: for method in ['MNE', 'dSPM', 'sLORETA']: stc = apply_inverse(evoked, inv, method=method) stc_vec = apply_inverse(evoked, inv, pick_ori='vector', method=method) assert_allclose(stc.data, stc_vec.magnitude().data) # Vector estimates don't work when using fixed orientations assert_raises(RuntimeError, apply_inverse, evoked, inv_3, pick_ori='vector') # When computing with vector fields, computing the difference between two # evokeds and then performing the inverse should yield the same result as # computing the difference between the inverses. evoked0 = read_evokeds(fname_data, condition=0, baseline=(None, 0)) evoked0.crop(0, 0.2) evoked1 = read_evokeds(fname_data, condition=1, baseline=(None, 0)) evoked1.crop(0, 0.2) diff = combine_evoked((evoked0, evoked1), [1, -1]) stc_diff = apply_inverse(diff, inv_1, method='MNE') stc_diff_vec = apply_inverse(diff, inv_1, method='MNE', pick_ori='vector') stc_vec0 = apply_inverse(evoked0, inv_1, method='MNE', pick_ori='vector') stc_vec1 = apply_inverse(evoked1, inv_1, method='MNE', pick_ori='vector') assert_allclose(stc_diff_vec.data, (stc_vec0 - stc_vec1).data) assert_allclose(stc_diff.data, (stc_vec0 - stc_vec1).magnitude().data)
def test_make_inverse_operator_vector(): """Test MNE inverse computation (vector result).""" fwd_surf = read_forward_solution_meg(fname_fwd, surf_ori=True) fwd_fixed = read_forward_solution_meg(fname_fwd, surf_ori=False) evoked = _get_evoked() noise_cov = read_cov(fname_cov) # Make different version of the inverse operator inv_1 = make_inverse_operator(evoked.info, fwd_fixed, noise_cov, loose=1) inv_2 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, depth=None, use_cps=True) inv_3 = make_inverse_operator(evoked.info, fwd_surf, noise_cov, fixed=True, use_cps=True) inv_4 = make_inverse_operator(evoked.info, fwd_fixed, noise_cov, loose=.2, depth=None) # Apply the inverse operators and check the result for ii, inv in enumerate((inv_1, inv_2, inv_4)): # Don't do eLORETA here as it will be quite slow methods = ['MNE', 'dSPM', 'sLORETA'] if ii < 2 else ['MNE'] for method in methods: stc = apply_inverse(evoked, inv, method=method) stc_vec = apply_inverse(evoked, inv, pick_ori='vector', method=method) assert_allclose(stc.data, stc_vec.magnitude().data) # Vector estimates don't work when using fixed orientations pytest.raises(RuntimeError, apply_inverse, evoked, inv_3, pick_ori='vector') # When computing with vector fields, computing the difference between two # evokeds and then performing the inverse should yield the same result as # computing the difference between the inverses. evoked0 = read_evokeds(fname_data, condition=0, baseline=(None, 0)) evoked0.crop(0, 0.2) evoked1 = read_evokeds(fname_data, condition=1, baseline=(None, 0)) evoked1.crop(0, 0.2) diff = combine_evoked((evoked0, evoked1), [1, -1]) stc_diff = apply_inverse(diff, inv_1, method='MNE') stc_diff_vec = apply_inverse(diff, inv_1, method='MNE', pick_ori='vector') stc_vec0 = apply_inverse(evoked0, inv_1, method='MNE', pick_ori='vector') stc_vec1 = apply_inverse(evoked1, inv_1, method='MNE', pick_ori='vector') assert_allclose(stc_diff_vec.data, (stc_vec0 - stc_vec1).data, atol=1e-20) assert_allclose(stc_diff.data, (stc_vec0 - stc_vec1).magnitude().data, atol=1e-20)
def test_apply_inverse_operator(): """Test MNE inverse application.""" inverse_operator = read_inverse_operator(fname_full) evoked = _get_evoked() # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) # Inverse has 306 channels - 4 proj = 302 assert_true(compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10e-9) assert_true(stc.data.mean() > 1e-11) # test if using prepared and not prepared inverse operator give the same # result inv_op = prepare_inverse_operator(inverse_operator, nave=evoked.nave, lambda2=lambda2, method="MNE") stc2 = apply_inverse(evoked, inv_op, lambda2, "MNE") assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 10.0) assert_true(stc.data.mean() > 0.1) stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert_true(stc.subject == 'sample') assert_true(stc.data.min() > 0) assert_true(stc.data.max() < 35) assert_true(stc.data.mean() > 0.1) # test without using a label (so delayed computation is used) label = read_label(fname_label % 'Aud-lh') stc = apply_inverse(evoked, inv_op, lambda2, "MNE") stc_label = apply_inverse(evoked, inv_op, lambda2, "MNE", label=label) assert_equal(stc_label.subject, 'sample') label_stc = stc.in_label(label) assert_true(label_stc.subject == 'sample') assert_allclose(stc_label.data, label_stc.data) # Test that no errors are raised with loose inverse ops and picking normals noise_cov = read_cov(fname_cov) fwd = read_forward_solution_meg(fname_fwd) inv_op2 = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1, fixed='auto', depth=None) apply_inverse(evoked, inv_op2, 1 / 9., method='MNE', pick_ori='normal') # Test we get errors when using custom ref or no average proj is present evoked.info['custom_ref_applied'] = True assert_raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") evoked.info['custom_ref_applied'] = False evoked.info['projs'] = [] # remove EEG proj assert_raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE")
def test_apply_inverse_operator(): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) inverse_operator = read_inverse_operator(fname_inv) evoked = _get_evoked() # Inverse has 306 channels - 4 proj = 302 assert (compute_rank_inverse(inverse_operator) == 302) # Inverse has 306 channels - 4 proj = 302 assert (compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 13e-9 assert stc.data.mean() > 1e-11 # test if using prepared and not prepared inverse operator give the same # result inv_op = prepare_inverse_operator(inverse_operator, nave=evoked.nave, lambda2=lambda2, method="MNE") stc2 = apply_inverse(evoked, inv_op, lambda2, "MNE") assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) # This is little more than a smoke test... stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 10.0 assert stc.data.mean() > 0.1 stc = apply_inverse(evoked, inverse_operator, lambda2, "eLORETA") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 3.0 assert stc.data.mean() > 0.1 stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 35 assert stc.data.mean() > 0.1 # test without using a label (so delayed computation is used) label = read_label(fname_label % 'Aud-lh') stc = apply_inverse(evoked, inv_op, lambda2, "MNE") stc_label = apply_inverse(evoked, inv_op, lambda2, "MNE", label=label) assert_equal(stc_label.subject, 'sample') label_stc = stc.in_label(label) assert label_stc.subject == 'sample' assert_allclose(stc_label.data, label_stc.data) # Test that no errors are raised with loose inverse ops and picking normals noise_cov = read_cov(fname_cov) fwd = read_forward_solution_meg(fname_fwd) inv_op_meg = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1, fixed='auto', depth=None) apply_inverse(evoked, inv_op_meg, 1 / 9., method='MNE', pick_ori='normal') # Test we get errors when using custom ref or no average proj is present evoked.info['custom_ref_applied'] = True pytest.raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") evoked.info['custom_ref_applied'] = False evoked.info['projs'] = [] # remove EEG proj pytest.raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") # But test that we do not get EEG-related errors on MEG-only inv (gh-4650) apply_inverse(evoked, inv_op_meg, 1. / 9.)
def test_apply_inverse_operator(evoked): """Test MNE inverse application.""" # use fname_inv as it will be faster than fname_full (fewer verts and chs) inverse_operator = read_inverse_operator(fname_inv) # Inverse has 306 channels - 4 proj = 302 assert (compute_rank_inverse(inverse_operator) == 302) # Inverse has 306 channels - 4 proj = 302 assert (compute_rank_inverse(inverse_operator) == 302) stc = apply_inverse(evoked, inverse_operator, lambda2, "MNE") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 13e-9 assert stc.data.mean() > 1e-11 # test if using prepared and not prepared inverse operator give the same # result inv_op = prepare_inverse_operator(inverse_operator, nave=evoked.nave, lambda2=lambda2, method="MNE") stc2 = apply_inverse(evoked, inv_op, lambda2, "MNE") assert_array_almost_equal(stc.data, stc2.data) assert_array_almost_equal(stc.times, stc2.times) # This is little more than a smoke test... stc = apply_inverse(evoked, inverse_operator, lambda2, "sLORETA") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 10.0 assert stc.data.mean() > 0.1 stc = apply_inverse(evoked, inverse_operator, lambda2, "eLORETA") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 3.0 assert stc.data.mean() > 0.1 stc = apply_inverse(evoked, inverse_operator, lambda2, "dSPM") assert stc.subject == 'sample' assert stc.data.min() > 0 assert stc.data.max() < 35 assert stc.data.mean() > 0.1 # test without using a label (so delayed computation is used) label = read_label(fname_label % 'Aud-lh') stc = apply_inverse(evoked, inv_op, lambda2, "MNE") stc_label = apply_inverse(evoked, inv_op, lambda2, "MNE", label=label) assert_equal(stc_label.subject, 'sample') label_stc = stc.in_label(label) assert label_stc.subject == 'sample' assert_allclose(stc_label.data, label_stc.data) # Test that no errors are raised with loose inverse ops and picking normals noise_cov = read_cov(fname_cov) fwd = read_forward_solution_meg(fname_fwd) inv_op_meg = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1, fixed='auto', depth=None) apply_inverse(evoked, inv_op_meg, 1 / 9., method='MNE', pick_ori='normal') # Test we get errors when using custom ref or no average proj is present evoked.info['custom_ref_applied'] = True pytest.raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") evoked.info['custom_ref_applied'] = False evoked.info['projs'] = [] # remove EEG proj pytest.raises(ValueError, apply_inverse, evoked, inv_op, lambda2, "MNE") # But test that we do not get EEG-related errors on MEG-only inv (gh-4650) apply_inverse(evoked, inv_op_meg, 1. / 9.)
def test_localization_bias(): """Test inverse localization bias for minimum-norm solvers.""" # Identity input evoked = _get_evoked() evoked.pick_types(meg=True, eeg=True, exclude=()) evoked = EvokedArray(np.eye(len(evoked.data)), evoked.info) noise_cov = read_cov(fname_cov) # restrict to limited set of verts (small src here) and one hemi for speed fwd_orig = read_forward_solution(fname_fwd) vertices = [fwd_orig['src'][0]['vertno'].copy(), []] stc = SourceEstimate(np.zeros((sum(len(v) for v in vertices), 1)), vertices, 0., 1.) fwd_orig = restrict_forward_to_stc(fwd_orig, stc) # # Fixed orientation (not very different) # fwd = fwd_orig.copy() inv_fixed = make_inverse_operator(evoked.info, fwd, noise_cov, loose=0., depth=0.8) fwd = convert_forward_solution(fwd, force_fixed=True, surf_ori=True) fwd = fwd['sol']['data'] want = np.arange(fwd.shape[1]) for method, lower, upper in (('MNE', 83, 87), ('dSPM', 96, 98), ('sLORETA', 100, 100), ('eLORETA', 100, 100)): inv_op = apply_inverse(evoked, inv_fixed, lambda2, method).data loc = np.abs(np.dot(inv_op, fwd)) # Compute the percentage of sources for which there is no localization # bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method # # Loose orientation # fwd = fwd_orig.copy() inv_free = make_inverse_operator(evoked.info, fwd, noise_cov, loose=0.2, depth=0.8) fwd = fwd['sol']['data'] want = np.arange(fwd.shape[1]) // 3 for method, lower, upper in (('MNE', 25, 35), ('dSPM', 25, 35), ('sLORETA', 35, 40), ('eLORETA', 40, 45)): inv_op = apply_inverse(evoked, inv_free, lambda2, method, pick_ori='vector').data loc = np.linalg.norm(np.einsum('vos,sx->vxo', inv_op, fwd), axis=-1) # Compute the percentage of sources for which there is no localization # bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method # # Free orientation # fwd = fwd_orig.copy() inv_free = make_inverse_operator(evoked.info, fwd, noise_cov, loose=1., depth=0.8) fwd = fwd['sol']['data'] want = np.arange(fwd.shape[1]) // 3 force_kwargs = dict(method_params=dict(force_equal=True)) for method, lower, upper, kwargs in (('MNE', 45, 55, {}), ('dSPM', 40, 45, {}), ('sLORETA', 90, 95, {}), ('eLORETA', 90, 95, force_kwargs), ('eLORETA', 100, 100, {}), ): inv_op = apply_inverse(evoked, inv_free, lambda2, method, pick_ori='vector', **kwargs).data loc = np.linalg.norm(np.einsum('vos,sx->vxo', inv_op, fwd), axis=-1) # Compute the percentage of sources for which there is no localization # bias: perc = (want == np.argmax(loc, axis=0)).mean() * 100 assert lower <= perc <= upper, method
def test_plot_source_estimates(renderer_interactive, all_src_types_inv_evoked, pick_ori, kind): """Test plotting of scalar and vector source estimates.""" invs, evoked = all_src_types_inv_evoked inv = invs[kind] is_pyvista = renderer_interactive._get_3d_backend() == 'pyvista' with pytest.warns(None): # PCA mag stc = apply_inverse(evoked, inv, pick_ori=pick_ori) stc.data[1] *= -1 # make it signed meth_key = 'plot_3d' if isinstance(stc, _BaseVolSourceEstimate) else 'plot' stc.subject = 'sample' meth = getattr(stc, meth_key) kwargs = dict( subjects_dir=subjects_dir, time_viewer=False, show_traces=False, # for speed smoothing_steps=1, verbose='error', src=inv['src'], volume_options=dict(resolution=None), # for speed ) if pick_ori != 'vector': kwargs['surface'] = 'white' # Mayavi can't handle non-surface if kind != 'surface' and not is_pyvista: with pytest.raises(RuntimeError, match='PyVista'): meth(**kwargs) return brain = meth(**kwargs) brain.close() del brain if pick_ori == 'vector': with pytest.raises(ValueError, match='use "pos_lims"'): meth(**kwargs, clim=dict(pos_lims=[1, 2, 3])) if kind in ('volume', 'mixed'): with pytest.raises(TypeError, match='when stc is a mixed or vol'): these_kwargs = kwargs.copy() these_kwargs.pop('src') meth(**these_kwargs) with pytest.raises(ValueError, match='cannot be used'): these_kwargs = kwargs.copy() these_kwargs.update(show_traces=True, time_viewer=False) meth(**these_kwargs) if not is_pyvista: with pytest.raises(ValueError, match='view_layout must be'): meth(view_layout='horizontal', **kwargs) # flatmaps (mostly a lot of error checking) these_kwargs = kwargs.copy() these_kwargs.update(surface='flat', views='auto') if kind == 'surface' and pick_ori != 'vector' and is_pyvista: with pytest.raises(FileNotFoundError, match='flatmap'): meth(**these_kwargs) # sample does not have them fs_stc = stc.copy() fs_stc.subject = 'fsaverage' # this is wrong, but don't have to care flat_meth = getattr(fs_stc, meth_key) these_kwargs.pop('src') if pick_ori == 'vector': pass # can't even pass "surface" variable elif kind != 'surface': with pytest.raises(TypeError, match='SourceEstimate when a flatmap'): flat_meth(**these_kwargs) elif not is_pyvista: with pytest.raises(RuntimeError, match='PyVista 3D backend.*flatmap'): flat_meth(**these_kwargs) else: brain = flat_meth(**these_kwargs) brain.close() these_kwargs.update(surface='inflated', views='flat') with pytest.raises(ValueError, match='surface="flat".*views="flat"'): flat_meth(**these_kwargs) # just test one for speed if kind != 'mixed': return assert is_pyvista brain = meth(views=['lat', 'med', 'ven'], hemi='lh', view_layout='horizontal', **kwargs) brain.close() assert brain._subplot_shape == (1, 3) del brain these_kwargs = kwargs.copy() these_kwargs['volume_options'] = dict(blending='foo') with pytest.raises(ValueError, match='mip'): meth(**these_kwargs) these_kwargs['volume_options'] = dict(badkey='foo') with pytest.raises(ValueError, match='unknown'): meth(**these_kwargs) # with resampling (actually downsampling but it's okay) these_kwargs['volume_options'] = dict(resolution=20., surface_alpha=0.) brain = meth(**these_kwargs) brain.close() del brain