def test_simulate_raw_bem(raw_data): """Test simulation of raw data with BEM.""" raw, src, stc, trans, sphere = raw_data src = setup_source_space('sample', 'oct1', subjects_dir=subjects_dir) for s in src: s['nuse'] = 3 s['vertno'] = src[1]['vertno'][:3] s['inuse'].fill(0) s['inuse'][s['vertno']] = 1 # use different / more complete STC here vertices = [s['vertno'] for s in src] stc = SourceEstimate(np.eye(sum(len(v) for v in vertices)), vertices, 0, 1. / raw.info['sfreq']) with pytest.deprecated_call(): raw_sim_sph = simulate_raw(raw, stc, trans, src, sphere, cov=None, verbose=True) with pytest.deprecated_call(): raw_sim_bem = simulate_raw(raw, stc, trans, src, bem_fname, cov=None, n_jobs=2) # some components (especially radial) might not match that well, # so just make sure that most components have high correlation assert_array_equal(raw_sim_sph.ch_names, raw_sim_bem.ch_names) picks = pick_types(raw.info, meg=True, eeg=True) n_ch = len(picks) corr = np.corrcoef(raw_sim_sph[picks][0], raw_sim_bem[picks][0]) assert_array_equal(corr.shape, (2 * n_ch, 2 * n_ch)) med_corr = np.median(np.diag(corr[:n_ch, -n_ch:])) assert med_corr > 0.65 # do some round-trip localization for s in src: transform_surface_to(s, 'head', trans) locs = np.concatenate([s['rr'][s['vertno']] for s in src]) tmax = (len(locs) - 1) / raw.info['sfreq'] cov = make_ad_hoc_cov(raw.info) # The tolerance for the BEM is surprisingly high (28) but I get the same # result when using MNE-C and Xfit, even when using a proper 5120 BEM :( for use_raw, bem, tol in ((raw_sim_sph, sphere, 2), (raw_sim_bem, bem_fname, 31)): events = find_events(use_raw, 'STI 014') assert len(locs) == 6 evoked = Epochs(use_raw, events, 1, 0, tmax, baseline=None).average() assert len(evoked.times) == len(locs) fits = fit_dipole(evoked, cov, bem, trans, min_dist=1.)[0].pos diffs = np.sqrt(np.sum((locs - fits)**2, axis=-1)) * 1000 med_diff = np.median(diffs) assert med_diff < tol, '%s: %s' % (bem, med_diff)
def test_simulate_raw_bem(raw_data): """Test simulation of raw data with BEM.""" raw, src, stc, trans, sphere = raw_data src = setup_source_space('sample', 'oct1', subjects_dir=subjects_dir) for s in src: s['nuse'] = 3 s['vertno'] = src[1]['vertno'][:3] s['inuse'].fill(0) s['inuse'][s['vertno']] = 1 # use different / more complete STC here vertices = [s['vertno'] for s in src] stc = SourceEstimate(np.eye(sum(len(v) for v in vertices)), vertices, 0, 1. / raw.info['sfreq']) with pytest.deprecated_call(): raw_sim_sph = simulate_raw(raw, stc, trans, src, sphere, cov=None, verbose=True) with pytest.deprecated_call(): raw_sim_bem = simulate_raw(raw, stc, trans, src, bem_fname, cov=None, n_jobs=2) # some components (especially radial) might not match that well, # so just make sure that most components have high correlation assert_array_equal(raw_sim_sph.ch_names, raw_sim_bem.ch_names) picks = pick_types(raw.info, meg=True, eeg=True) n_ch = len(picks) corr = np.corrcoef(raw_sim_sph[picks][0], raw_sim_bem[picks][0]) assert_array_equal(corr.shape, (2 * n_ch, 2 * n_ch)) med_corr = np.median(np.diag(corr[:n_ch, -n_ch:])) assert med_corr > 0.65 # do some round-trip localization for s in src: transform_surface_to(s, 'head', trans) locs = np.concatenate([s['rr'][s['vertno']] for s in src]) tmax = (len(locs) - 1) / raw.info['sfreq'] cov = make_ad_hoc_cov(raw.info) # The tolerance for the BEM is surprisingly high (28) but I get the same # result when using MNE-C and Xfit, even when using a proper 5120 BEM :( for use_raw, bem, tol in ((raw_sim_sph, sphere, 2), (raw_sim_bem, bem_fname, 31)): events = find_events(use_raw, 'STI 014') assert len(locs) == 6 evoked = Epochs(use_raw, events, 1, 0, tmax, baseline=None).average() assert len(evoked.times) == len(locs) fits = fit_dipole(evoked, cov, bem, trans, min_dist=1.)[0].pos diffs = np.sqrt(np.sum((locs - fits) ** 2, axis=-1)) * 1000 med_diff = np.median(diffs) assert med_diff < tol, '%s: %s' % (bem, med_diff)
def test_dipole_fitting(): """Test dipole fitting""" amp = 10e-9 tempdir = _TempDir() rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, 'test.dip') fname_sim = op.join(tempdir, 'test-ave.fif') fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [np.sort(rng.permutation(s['vertno'])[:n_per_hemi]) for s in fwd['src']] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) with warnings.catch_warnings(record=True): # semi-def cov evoked = generate_evoked(fwd, stc, evoked, cov, snr=20, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort(np.concatenate([ pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2]])) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess([ 'mne_dipole_fit', '--meas', fname_sim, '--meg', '--eeg', '--noise', fname_cov, '--dip', fname_dtemp, '--mri', fname_fwd, '--reg', '0', '--tmin', '0', ]) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) dip, residuals = fit_dipole(evoked, fname_cov, sphere, fname_fwd) # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data ** 2, axis=0)) resi_rms = np.sqrt(np.sum(residuals ** 2, axis=0)) assert_true((data_rms > resi_rms).all()) # Compare to original points transform_surface_to(fwd['src'][0], 'head', fwd['mri_head_t']) transform_surface_to(fwd['src'][1], 'head', fwd['mri_head_t']) src_rr = np.concatenate([s['rr'][v] for s, v in zip(fwd['src'], vertices)], axis=0) src_nn = np.concatenate([s['nn'][v] for s, v in zip(fwd['src'], vertices)], axis=0) # MNE-C skips the last "time" point :( dip.crop(dip_c.times[0], dip_c.times[-1]) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did at least as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1)))] amp_errs += [np.sqrt(np.mean((amp - d.amplitude) ** 2))] gofs += [np.mean(d.gof)] assert_true(dists[0] >= dists[1], 'dists: %s' % dists) assert_true(corrs[0] <= corrs[1], 'corrs: %s' % corrs) assert_true(gc_dists[0] >= gc_dists[1], 'gc-dists (ori): %s' % gc_dists) assert_true(amp_errs[0] >= amp_errs[1], 'amplitude errors: %s' % amp_errs)
def test_dipole_fitting(): """Test dipole fitting.""" amp = 100e-9 tempdir = _TempDir() rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, 'test.dip') fname_sim = op.join(tempdir, 'test-ave.fif') fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True, use_cps=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [ np.sort(rng.permutation(s['vertno'])[:n_per_hemi]) for s in fwd['src'] ] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) evoked = simulate_evoked(fwd, stc, evoked.info, cov, nave=evoked.nave, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort( np.concatenate([ pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2] ])) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess([ 'mne_dipole_fit', '--meas', fname_sim, '--meg', '--eeg', '--noise', fname_cov, '--dip', fname_dtemp, '--mri', fname_fwd, '--reg', '0', '--tmin', '0', ]) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) with pytest.warns(RuntimeWarning, match='projection'): dip, residuals = fit_dipole(evoked, cov, sphere, fname_fwd) # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data**2, axis=0)) resi_rms = np.sqrt(np.sum(residuals**2, axis=0)) assert (data_rms > resi_rms * 0.95).all(), \ '%s (factor: %s)' % ((data_rms / resi_rms).min(), 0.95) # Compare to original points transform_surface_to(fwd['src'][0], 'head', fwd['mri_head_t']) transform_surface_to(fwd['src'][1], 'head', fwd['mri_head_t']) assert_equal(fwd['src'][0]['coord_frame'], FIFF.FIFFV_COORD_HEAD) src_rr = np.concatenate([s['rr'][v] for s, v in zip(fwd['src'], vertices)], axis=0) src_nn = np.concatenate([s['nn'][v] for s, v in zip(fwd['src'], vertices)], axis=0) # MNE-C skips the last "time" point :( out = dip.crop(dip_c.times[0], dip_c.times[-1]) assert (dip is out) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did about as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [ 180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1))) ] amp_errs += [np.sqrt(np.mean((amp - d.amplitude)**2))] gofs += [np.mean(d.gof)] if os.getenv('TRAVIS', 'false').lower() == 'true' and \ 'OPENBLAS_NUM_THREADS' in os.environ: # XXX possibly some OpenBLAS numerical differences make # things slightly worse for us factor = 0.7 else: factor = 0.8 assert dists[0] / factor >= dists[1], 'dists: %s' % dists assert corrs[0] * factor <= corrs[1], 'corrs: %s' % corrs assert gc_dists[0] / factor >= gc_dists[1] * 0.8, \ 'gc-dists (ori): %s' % gc_dists assert amp_errs[0] / factor >= amp_errs[1],\ 'amplitude errors: %s' % amp_errs # This one is weird because our cov/sim/picking is weird assert gofs[0] * factor <= gofs[1] * 2, 'gof: %s' % gofs
def test_dipole_fitting(): """Test dipole fitting.""" amp = 10e-9 tempdir = _TempDir() rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, 'test.dip') fname_sim = op.join(tempdir, 'test-ave.fif') fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [np.sort(rng.permutation(s['vertno'])[:n_per_hemi]) for s in fwd['src']] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) evoked = simulate_evoked(fwd, stc, evoked.info, cov, snr=20, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort(np.concatenate([ pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2]])) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess([ 'mne_dipole_fit', '--meas', fname_sim, '--meg', '--eeg', '--noise', fname_cov, '--dip', fname_dtemp, '--mri', fname_fwd, '--reg', '0', '--tmin', '0', ]) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) dip, residuals = fit_dipole(evoked, fname_cov, sphere, fname_fwd) # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data ** 2, axis=0)) resi_rms = np.sqrt(np.sum(residuals ** 2, axis=0)) factor = 1. # XXX weird, inexplicable differenc for 3.5 build we'll assume is due to # Anaconda bug for now... if os.getenv('TRAVIS', 'false') == 'true' and \ sys.version[:3] in ('3.5', '2.7'): factor = 0.8 assert_true((data_rms > factor * resi_rms).all(), msg='%s (factor: %s)' % ((data_rms / resi_rms).min(), factor)) # Compare to original points transform_surface_to(fwd['src'][0], 'head', fwd['mri_head_t']) transform_surface_to(fwd['src'][1], 'head', fwd['mri_head_t']) src_rr = np.concatenate([s['rr'][v] for s, v in zip(fwd['src'], vertices)], axis=0) src_nn = np.concatenate([s['nn'][v] for s, v in zip(fwd['src'], vertices)], axis=0) # MNE-C skips the last "time" point :( dip.crop(dip_c.times[0], dip_c.times[-1]) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did at least as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1)))] amp_errs += [np.sqrt(np.mean((amp - d.amplitude) ** 2))] gofs += [np.mean(d.gof)] assert_true(dists[0] >= dists[1] * factor, 'dists: %s' % dists) assert_true(corrs[0] <= corrs[1] / factor, 'corrs: %s' % corrs) assert_true(gc_dists[0] >= gc_dists[1] * factor, 'gc-dists (ori): %s' % gc_dists) assert_true(amp_errs[0] >= amp_errs[1] * factor, 'amplitude errors: %s' % amp_errs) assert_true(gofs[0] <= gofs[1] / factor, 'gof: %s' % gofs)
def test_simulate_raw_bem(raw_data): """Test simulation of raw data with BEM.""" raw, src_ss, stc, trans, sphere = raw_data src = setup_source_space('sample', 'oct1', subjects_dir=subjects_dir) for s in src: s['nuse'] = 3 s['vertno'] = src[1]['vertno'][:3] s['inuse'].fill(0) s['inuse'][s['vertno']] = 1 # use different / more complete STC here vertices = [s['vertno'] for s in src] stc = SourceEstimate(np.eye(sum(len(v) for v in vertices)), vertices, 0, 1. / raw.info['sfreq']) stcs = [stc] * 15 raw_sim_sph = simulate_raw(raw.info, stcs, trans, src, sphere) raw_sim_bem = simulate_raw(raw.info, stcs, trans, src, bem_fname) # some components (especially radial) might not match that well, # so just make sure that most components have high correlation assert_array_equal(raw_sim_sph.ch_names, raw_sim_bem.ch_names) picks = pick_types(raw.info, meg=True, eeg=True) n_ch = len(picks) corr = np.corrcoef(raw_sim_sph[picks][0], raw_sim_bem[picks][0]) assert_array_equal(corr.shape, (2 * n_ch, 2 * n_ch)) med_corr = np.median(np.diag(corr[:n_ch, -n_ch:])) assert med_corr > 0.65 # do some round-trip localization for s in src: transform_surface_to(s, 'head', trans) locs = np.concatenate([s['rr'][s['vertno']] for s in src]) tmax = (len(locs) - 1) / raw.info['sfreq'] cov = make_ad_hoc_cov(raw.info) # The tolerance for the BEM is surprisingly high (28) but I get the same # result when using MNE-C and Xfit, even when using a proper 5120 BEM :( for use_raw, bem, tol in ((raw_sim_sph, sphere, 2), (raw_sim_bem, bem_fname, 31)): events = find_events(use_raw, 'STI 014') assert len(locs) == 6 evoked = Epochs(use_raw, events, 1, 0, tmax, baseline=None).average() assert len(evoked.times) == len(locs) fits = fit_dipole(evoked, cov, bem, trans, min_dist=1.)[0].pos diffs = np.sqrt(np.sum((locs - fits) ** 2, axis=-1)) * 1000 med_diff = np.median(diffs) assert med_diff < tol, '%s: %s' % (bem, med_diff) # also test event timings with SourceSimulator first_samp = raw.first_samp events = find_events(raw, initial_event=True, verbose=False) evt_times = events[:, 0] assert len(events) == 3 labels_sim = [[], [], []] # random l+r hemisphere points labels_sim[0] = Label([src_ss[0]['vertno'][1]], hemi='lh') labels_sim[1] = Label([src_ss[0]['vertno'][4]], hemi='lh') labels_sim[2] = Label([src_ss[1]['vertno'][2]], hemi='rh') wf_sim = np.array([2, 1, 0]) for this_fs in (0, first_samp): ss = SourceSimulator(src_ss, 1. / raw.info['sfreq'], first_samp=this_fs) for i in range(3): ss.add_data(labels_sim[i], wf_sim, events[np.newaxis, i]) assert ss.n_times == evt_times[-1] + len(wf_sim) - this_fs raw_sim = simulate_raw(raw.info, ss, src=src_ss, bem=bem_fname, first_samp=first_samp) data = raw_sim.get_data() amp0 = data[:, evt_times - first_samp].max() amp1 = data[:, evt_times + 1 - first_samp].max() amp2 = data[:, evt_times + 2 - first_samp].max() assert_allclose(amp0 / amp1, wf_sim[0] / wf_sim[1], rtol=1e-5) assert amp2 == 0 assert raw_sim.n_times == ss.n_times
def test_dipole_fitting(): """Test dipole fitting""" amp = 10e-9 tempdir = _TempDir() rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, "test.dip") fname_sim = op.join(tempdir, "test-ave.fif") fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [np.sort(rng.permutation(s["vertno"])[:n_per_hemi]) for s in fwd["src"]] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) evoked = simulate_evoked(fwd, stc, evoked.info, cov, snr=20, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort( np.concatenate( [pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2]] ) ) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess( [ "mne_dipole_fit", "--meas", fname_sim, "--meg", "--eeg", "--noise", fname_cov, "--dip", fname_dtemp, "--mri", fname_fwd, "--reg", "0", "--tmin", "0", ] ) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) dip, residuals = fit_dipole(evoked, fname_cov, sphere, fname_fwd) # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data ** 2, axis=0)) resi_rms = np.sqrt(np.sum(residuals ** 2, axis=0)) factor = 1.0 # XXX weird, inexplicable differenc for 3.5 build we'll assume is due to # Anaconda bug for now... if os.getenv("TRAVIS", "false") == "true" and sys.version[:3] in ("3.5", "2.7"): factor = 0.8 assert_true((data_rms > factor * resi_rms).all(), msg="%s (factor: %s)" % ((data_rms / resi_rms).min(), factor)) # Compare to original points transform_surface_to(fwd["src"][0], "head", fwd["mri_head_t"]) transform_surface_to(fwd["src"][1], "head", fwd["mri_head_t"]) src_rr = np.concatenate([s["rr"][v] for s, v in zip(fwd["src"], vertices)], axis=0) src_nn = np.concatenate([s["nn"][v] for s, v in zip(fwd["src"], vertices)], axis=0) # MNE-C skips the last "time" point :( dip.crop(dip_c.times[0], dip_c.times[-1]) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did at least as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1)))] amp_errs += [np.sqrt(np.mean((amp - d.amplitude) ** 2))] gofs += [np.mean(d.gof)] assert_true(dists[0] >= dists[1] * factor, "dists: %s" % dists) assert_true(corrs[0] <= corrs[1] / factor, "corrs: %s" % corrs) assert_true(gc_dists[0] >= gc_dists[1] * factor, "gc-dists (ori): %s" % gc_dists) assert_true(amp_errs[0] >= amp_errs[1] * factor, "amplitude errors: %s" % amp_errs) assert_true(gofs[0] <= gofs[1] / factor, "gof: %s" % gofs)
def test_dipole_fitting(tmp_path): """Test dipole fitting.""" amp = 100e-9 tempdir = str(tmp_path) rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, 'test.dip') fname_sim = op.join(tempdir, 'test-ave.fif') fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True, use_cps=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [ np.sort(rng.permutation(s['vertno'])[:n_per_hemi]) for s in fwd['src'] ] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) evoked = simulate_evoked(fwd, stc, evoked.info, cov, nave=evoked.nave, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort( np.concatenate([ pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2] ])) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess([ 'mne_dipole_fit', '--meas', fname_sim, '--meg', '--eeg', '--noise', fname_cov, '--dip', fname_dtemp, '--mri', fname_fwd, '--reg', '0', '--tmin', '0', ]) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) with pytest.warns(RuntimeWarning, match='projection'): dip, residual = fit_dipole(evoked, cov, sphere, fname_fwd, rank='info') # just to test rank support assert isinstance(residual, Evoked) # Test conversion of dip.pos to MNI coordinates. dip_mni_pos = dip.to_mni('sample', fname_trans, subjects_dir=subjects_dir) head_to_mni_dip_pos = head_to_mni(dip.pos, 'sample', fwd['mri_head_t'], subjects_dir=subjects_dir) assert_allclose(dip_mni_pos, head_to_mni_dip_pos, rtol=1e-3, atol=0) # Test finding label for dip.pos in an aseg, also tests `to_mri` target_labels = [ 'Left-Cerebral-Cortex', 'Unknown', 'Left-Cerebral-Cortex', 'Right-Cerebral-Cortex', 'Left-Cerebral-Cortex', 'Unknown', 'Unknown', 'Unknown', 'Right-Cerebral-White-Matter', 'Right-Cerebral-Cortex' ] labels = dip.to_volume_labels(fname_trans, subject='fsaverage', aseg="aseg", subjects_dir=subjects_dir) assert labels == target_labels # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data**2, axis=0)) resi_rms = np.sqrt(np.sum(residual.data**2, axis=0)) assert (data_rms > resi_rms * 0.95).all(), \ '%s (factor: %s)' % ((data_rms / resi_rms).min(), 0.95) # Compare to original points transform_surface_to(fwd['src'][0], 'head', fwd['mri_head_t']) transform_surface_to(fwd['src'][1], 'head', fwd['mri_head_t']) assert fwd['src'][0]['coord_frame'] == FIFF.FIFFV_COORD_HEAD src_rr = np.concatenate([s['rr'][v] for s, v in zip(fwd['src'], vertices)], axis=0) src_nn = np.concatenate([s['nn'][v] for s, v in zip(fwd['src'], vertices)], axis=0) # MNE-C skips the last "time" point :( out = dip.crop(dip_c.times[0], dip_c.times[-1]) assert (dip is out) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did about as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [ 180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1))) ] amp_errs += [np.sqrt(np.mean((amp - d.amplitude)**2))] gofs += [np.mean(d.gof)] # XXX possibly some OpenBLAS numerical differences make # things slightly worse for us factor = 0.7 assert dists[0] / factor >= dists[1], 'dists: %s' % dists assert corrs[0] * factor <= corrs[1], 'corrs: %s' % corrs assert gc_dists[0] / factor >= gc_dists[1] * 0.8, \ 'gc-dists (ori): %s' % gc_dists assert amp_errs[0] / factor >= amp_errs[1],\ 'amplitude errors: %s' % amp_errs # This one is weird because our cov/sim/picking is weird assert gofs[0] * factor <= gofs[1] * 2, 'gof: %s' % gofs
def test_dipole_fitting(): """Test dipole fitting.""" amp = 100e-9 tempdir = _TempDir() rng = np.random.RandomState(0) fname_dtemp = op.join(tempdir, 'test.dip') fname_sim = op.join(tempdir, 'test-ave.fif') fwd = convert_forward_solution(read_forward_solution(fname_fwd), surf_ori=False, force_fixed=True, use_cps=True) evoked = read_evokeds(fname_evo)[0] cov = read_cov(fname_cov) n_per_hemi = 5 vertices = [np.sort(rng.permutation(s['vertno'])[:n_per_hemi]) for s in fwd['src']] nv = sum(len(v) for v in vertices) stc = SourceEstimate(amp * np.eye(nv), vertices, 0, 0.001) evoked = simulate_evoked(fwd, stc, evoked.info, cov, nave=evoked.nave, random_state=rng) # For speed, let's use a subset of channels (strange but works) picks = np.sort(np.concatenate([ pick_types(evoked.info, meg=True, eeg=False)[::2], pick_types(evoked.info, meg=False, eeg=True)[::2]])) evoked.pick_channels([evoked.ch_names[p] for p in picks]) evoked.add_proj(make_eeg_average_ref_proj(evoked.info)) write_evokeds(fname_sim, evoked) # Run MNE-C version run_subprocess([ 'mne_dipole_fit', '--meas', fname_sim, '--meg', '--eeg', '--noise', fname_cov, '--dip', fname_dtemp, '--mri', fname_fwd, '--reg', '0', '--tmin', '0', ]) dip_c = read_dipole(fname_dtemp) # Run mne-python version sphere = make_sphere_model(head_radius=0.1) with pytest.warns(RuntimeWarning, match='projection'): dip, residual = fit_dipole(evoked, cov, sphere, fname_fwd) assert isinstance(residual, Evoked) # Sanity check: do our residuals have less power than orig data? data_rms = np.sqrt(np.sum(evoked.data ** 2, axis=0)) resi_rms = np.sqrt(np.sum(residual.data ** 2, axis=0)) assert (data_rms > resi_rms * 0.95).all(), \ '%s (factor: %s)' % ((data_rms / resi_rms).min(), 0.95) # Compare to original points transform_surface_to(fwd['src'][0], 'head', fwd['mri_head_t']) transform_surface_to(fwd['src'][1], 'head', fwd['mri_head_t']) assert_equal(fwd['src'][0]['coord_frame'], FIFF.FIFFV_COORD_HEAD) src_rr = np.concatenate([s['rr'][v] for s, v in zip(fwd['src'], vertices)], axis=0) src_nn = np.concatenate([s['nn'][v] for s, v in zip(fwd['src'], vertices)], axis=0) # MNE-C skips the last "time" point :( out = dip.crop(dip_c.times[0], dip_c.times[-1]) assert (dip is out) src_rr, src_nn = src_rr[:-1], src_nn[:-1] # check that we did about as well corrs, dists, gc_dists, amp_errs, gofs = [], [], [], [], [] for d in (dip_c, dip): new = d.pos diffs = new - src_rr corrs += [np.corrcoef(src_rr.ravel(), new.ravel())[0, 1]] dists += [np.sqrt(np.mean(np.sum(diffs * diffs, axis=1)))] gc_dists += [180 / np.pi * np.mean(np.arccos(np.sum(src_nn * d.ori, axis=1)))] amp_errs += [np.sqrt(np.mean((amp - d.amplitude) ** 2))] gofs += [np.mean(d.gof)] # XXX possibly some OpenBLAS numerical differences make # things slightly worse for us factor = 0.7 assert dists[0] / factor >= dists[1], 'dists: %s' % dists assert corrs[0] * factor <= corrs[1], 'corrs: %s' % corrs assert gc_dists[0] / factor >= gc_dists[1] * 0.8, \ 'gc-dists (ori): %s' % gc_dists assert amp_errs[0] / factor >= amp_errs[1],\ 'amplitude errors: %s' % amp_errs # This one is weird because our cov/sim/picking is weird assert gofs[0] * factor <= gofs[1] * 2, 'gof: %s' % gofs