-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TEST] Playing around with fixed dipole orientation in a discrete source space #10440
Conversation
This works for me:
But indeed with depth weighting, |
Ah, I needed to clarify better: constructing a volume or discrete forward model with fixed dipole orientations is no problem at all. It's when you attempt to use it to perform source modeling. the |
What makes volume special in this regard? |
When doing
|
note that with so few dipoles mne.inverse_sparse.mixed_norm should be used with alpha almost set to 0. |
In that case, would plain MNE also work here? What is the added benefit of the sparse solver? |
(@larsoner recommended MxNE in the forum thread) |
you will get a set of dipoles instances with MxNE code
… Message ID: ***@***.***>
|
With explained variance per dipole (though you could figure it out for MNE the same way I think). Otherwise, assuming you use a very small lambda2 for MNE, the total exp var should be similar. Would make a nice little unit test! |
A test that passes: import mne
import numpy as np
import matplotlib.pyplot as plt
# Read phantom data
data_path = mne.datasets.brainstorm.bst_phantom_elekta.data_path(verbose=True)
raw = mne.io.read_raw_fif(f'{data_path}/kojak_all_200nAm_pp_no_chpi_no_ms_raw.fif')
events = mne.find_events(raw, 'STI201')
# Extract evoked data for 2 dipoles
epochs = mne.Epochs(raw, events, [1, 17], tmin=-0.1, tmax=0.1, baseline=(-0.1, -0.05))
evoked_dip1 = epochs['1'].average()
evoked_dip2 = epochs['17'].average()
# Create an evoked with both dipole active at the same time
evoked = mne.combine_evoked([evoked_dip1, evoked_dip2], [1, 1])
# Fit two dipoles
cov = mne.compute_covariance(epochs, tmax=-0.05)
bem = mne.make_sphere_model(r0=[0, 0, 0], head_radius=0.08)
dip1, _ = mne.fit_dipole(evoked_dip1.copy().crop(0.035, 0.035), cov, bem)
dip2, _ = mne.fit_dipole(evoked_dip2.copy().crop(0.035, 0.035), cov, bem)
# Collect the dipoles in a single `Dipole` object
dips = mne.Dipole(
times=np.hstack((dip1.times, dip2.times)),
pos=np.vstack((dip1.pos, dip2.pos)),
ori=np.vstack((dip1.ori, dip2.ori)),
amplitude=np.hstack((dip1.amplitude, dip2.amplitude)),
gof=np.hstack((dip1.gof, dip2.gof)),
name=None,
conf=None,
khi2=np.hstack((dip1.khi2, dip2.khi2)),
nfree=dip1.nfree,
)
# Compute dipole timecourses using both MxNE and plain MNE
fwd, _ = mne.make_forward_dipole(dips, bem, evoked.info)
inv = mne.minimum_norm.make_inverse_operator(evoked.info, fwd, cov, fixed=True, depth=0)
stc_mxne = mne.inverse_sparse.mixed_norm(evoked, fwd, cov)
stc_mne = mne.minimum_norm.apply_inverse(evoked, inv, method='MNE')
# Plot the timecourses
plt.plot(evoked.times, stc_mxne.data.T)
plt.plot(evoked.times, stc_mne.data.T) |
pretty reassuring ! thx @wmvanvliet for the code snippet |
Closing in favor of #10464 |
Trying to see what it takes to perform MxNE using a source space that consists of two dipoles with fixed orientation. Currently, MNE doesn't support forward models with fixed orientation that are not of type
'surface'
. In this PR I'm disabling these checks and see what happens.Here is some example code that creates such a forward model and attempts to perform MxNE source estimation with it: