"""
.. _tut-point-spread:
======================================
Corrupt known signal with point spread
======================================
The aim of this tutorial is to demonstrate how to put a known signal at a
desired location(s) in a :class:`mne.SourceEstimate` and then corrupt the
signal with point-spread by applying a forward and inverse solution.
"""
import numpy as np
import mne
from mne.datasets import sample
from mne.minimum_norm import apply_inverse, read_inverse_operator
from mne.simulation import simulate_evoked, simulate_stc
seed = 199
method = "sLORETA"
snr = 3.0
lambda2 = 1.0 / snr**2
nave = np.inf
T = 100
times = np.linspace(0, 1, T)
dt = times[1] - times[0]
data_path = sample.data_path()
subjects_dir = data_path / "subjects"
fname_fwd = data_path / "MEG" / "sample" / "sample_audvis-meg-oct-6-fwd.fif"
fname_inv = data_path / "MEG" / "sample" / "sample_audvis-meg-oct-6-meg-fixed-inv.fif"
fname_evoked = data_path / "MEG" / "sample" / "sample_audvis-ave.fif"
fwd = mne.read_forward_solution(fname_fwd)
fwd = mne.convert_forward_solution(fwd, force_fixed=True, surf_ori=True, use_cps=False)
fwd["info"]["bads"] = []
inv_op = read_inverse_operator(fname_inv)
raw = mne.io.read_raw_fif(data_path / "MEG" / "sample" / "sample_audvis_raw.fif")
raw.info["bads"] = []
raw.set_eeg_reference(projection=True)
events = mne.find_events(raw)
event_id = {"Auditory/Left": 1, "Auditory/Right": 2}
epochs = mne.Epochs(raw, events, event_id, baseline=(None, 0), preload=True)
evoked = epochs.average()
labels = mne.read_labels_from_annot("sample", subjects_dir=subjects_dir)
label_names = [label.name for label in labels]
n_labels = len(labels)
cov = mne.compute_covariance(epochs, tmin=None, tmax=0.0)
signal = np.zeros((n_labels, T))
idx = label_names.index("inferiorparietal-lh")
signal[idx, :] = 1e-7 * np.sin(5 * 2 * np.pi * times)
idx = label_names.index("rostralmiddlefrontal-rh")
signal[idx, :] = 1e-7 * np.sin(7 * 2 * np.pi * times)
hemi_to_ind = {"lh": 0, "rh": 1}
for i, label in enumerate(labels):
labels[i].values.fill(1.0)
surf_vertices = fwd["src"][hemi_to_ind[label.hemi]]["vertno"]
restrict_verts = np.intersect1d(surf_vertices, label.vertices)
com = labels[i].center_of_mass(
subjects_dir=subjects_dir, restrict_vertices=restrict_verts, surf="white"
)
cent_idx = np.where(label.vertices == com)[0][0]
labels[i].values.fill(0.0)
labels[i].values[cent_idx] = 1.0
if "transversetemporal" in label.name:
dist, _ = label.distances_to_outside(subjects_dir=subjects_dir)
dist = dist[cent_idx]
area = label.compute_area(subjects_dir=subjects_dir)
r = np.sqrt(area / np.pi)
print(
f"{label.name} COM vertex is {dist * 1e3:0.1f} mm from edge "
f"(label area equivalent to a circle with r={r * 1e3:0.1f} mm)"
)
stc_gen = simulate_stc(fwd["src"], labels, signal, times[0], dt, value_fun=lambda x: x)
kwargs = dict(
subjects_dir=subjects_dir,
hemi="split",
smoothing_steps=4,
time_unit="s",
initial_time=0.05,
size=1200,
views=["lat", "med"],
)
clim = dict(kind="value", pos_lims=[1e-9, 1e-8, 1e-7])
brain_gen = stc_gen.plot(clim=clim, **kwargs)
evoked_gen = simulate_evoked(fwd, stc_gen, evoked.info, cov, nave, rng=seed)
stc_inv = apply_inverse(evoked_gen, inv_op, lambda2, method=method)
brain_inv = stc_inv.plot(**kwargs)