Description of the problem
I get a bug deep in the forward code when trying to simulate raw data with head movement.
Steps to reproduce
import numpy as np
import mne
from mne.simulation import SourceSimulator
# Use MNE sample data paths
sample_path = mne.datasets.sample.data_path()
subjects_dir = sample_path / 'subjects'
subject = 'sample'
# Load info from an evoked file
evoked_fname = sample_path / 'MEG/sample/sample_audvis-ave.fif'
evoked = mne.read_evokeds(evoked_fname, condition=0, baseline=(None, 0))
info = evoked.info.copy()
sfreq = info['sfreq']
# Forward stuff
bem = subjects_dir / subject / 'bem' / f'{subject}-5120-5120-5120-bem-sol.fif'
trans = mne.read_trans(sample_path / "MEG" / "sample" / "sample_audvis_raw-trans.fif")
src = mne.read_source_spaces(subjects_dir / subject / 'bem' / f'{subject}-oct-6-src.fif')
selected_label = mne.read_labels_from_annot(
subject, regexp="caudalmiddlefrontal-lh", subjects_dir=subjects_dir
)[0]
location = 1915 # Use the index of the vertex as a seed
extent = 0.0 # One dipole source
label_dipole = mne.label.select_sources(
subject,
selected_label,
location=location,
extent=extent,
subjects_dir=subjects_dir,
random_state=42,
)
# Minimal SourceSimulator
duration = 10. # seconds
sim = SourceSimulator(src, tstep=1.0 / sfreq, duration=duration)
n_times = int(duration * sfreq)
source_time_series = np.sin(2 * np.pi * 10 * np.arange(n_times) / sfreq) * 1e-9
sim.add_data(label_dipole, source_time_series, events=np.array([[0, 0, 1]]))
# Minimal head movement: dict with time points as keys
t1, t2 = 0, duration / 2
trans_matrices = {t1: info['dev_head_t']['trans'],
t2: info['dev_head_t']['trans']}
# Simulate raw
n_events = 10
events = np.zeros((n_events, 3), int)
events[:, 0] = np.random.choice(int(duration * sfreq), n_events,
replace=False)
events[:, 2] = 1
sim = SourceSimulator(src, tstep=1. / info['sfreq'],
duration=duration)
sim.add_data(label_dipole, source_time_series, events)
raw = mne.simulation.simulate_raw(
info, sim, forward=None, src=src,
head_pos=trans_matrices, bem=bem, trans=trans
)
Link to data
No response
Expected results
No error and raw data
Actual results
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
File ~/Desktop/04_github_repos/mne-opm/examples/reproduce_bug.py:59
56 sim = SourceSimulator(src, tstep=1. / info['sfreq'],
57 duration=duration)
58 sim.add_data(label_dipole, source_time_series, events)
---> 59 raw = mne.simulation.simulate_raw(
60 info, sim, forward=None, src=src,
61 head_pos=trans_matrices, bem=bem, trans=trans
62 )
File <decorator-gen-408>:12, in simulate_raw(info, stc, trans, src, bem, head_pos, mindist, interp, n_jobs, use_cps, forward, first_samp, max_iter, verbose)
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/simulation/raw.py:364, in simulate_raw(info, stc, trans, src, bem, head_pos, mindist, interp, n_jobs, use_cps, forward, first_samp, max_iter, verbose)
362 raw_datas.append(this_data)
363 # Stim channel
--> 364 fwd, fi = interper.feed(this_stop - this_start)
365 fi = fi[0]
366 stc_data, stim_data, _ = _stc_data_event(
367 stc_counted, fi, info["sfreq"], get_fwd.src, None if n == 0 else verts
368 )
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/_ola.py:190, in _Interp2.feed(self, n_pts)
188 # Convenience function for assembly
189 out_arrays = None
--> 190 for o in self.feed_generator(n_pts):
191 if out_arrays is None:
192 out_arrays = [
193 np.empty(v.shape + (n_pts,)) if v is not None else None
194 for v in o[1]
195 ]
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/_ola.py:131, in _Interp2.feed_generator(self, n_pts)
129 eval_pt = self.control_points[self._left_idx + 1]
130 logger.debug(f" Eval @ {self._left_idx + 1} ({eval_pt})")
--> 131 self._right = self.values(eval_pt)
132 assert self._right is not None
133 left_point = self.control_points[self._left_idx]
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/simulation/raw.py:770, in _SimForwards.__call__(self, offset)
768 assert self.offsets[self.idx] == offset
769 self.idx += 1
--> 770 fwd = next(self.iter)
771 self.src = fwd["src"]
772 # XXX eventually we could speed this up by allowing the forward
773 # solution code to only compute the normal direction
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/simulation/raw.py:863, in _iter_forward_solutions(***failed resolving arguments***)
858 if not outside.all():
859 raise RuntimeError(
860 f"{np.sum(~outside)} MEG sensors collided with inner skull "
861 f"surface for transform {ti}"
862 )
--> 863 megfwd = _compute_forwards(
864 rr, sensors=sensors, bem=bem, n_jobs=n_jobs, verbose=False
865 )["meg"]
866 megfwd = _to_forward_dict(megfwd, megnames)
867 else:
File <decorator-gen-354>:10, in _compute_forwards(rr, bem, sensors, n_jobs, verbose)
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/forward/_compute_forward.py:838, in _compute_forwards(rr, bem, sensors, n_jobs, verbose)
836 _check_option("solver", solver, ("mne", "openmeeg"))
837 if bem["is_sphere"] or solver == "mne":
--> 838 fwd_data = _prep_field_computation(rr, sensors=sensors, bem=bem, n_jobs=n_jobs)
839 Bs = _compute_forwards_meeg(
840 rr, sensors=sensors, fwd_data=fwd_data, n_jobs=n_jobs
841 )
842 else:
File <decorator-gen-353>:12, in _prep_field_computation(rr, sensors, bem, n_jobs, verbose)
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/forward/_compute_forward.py:755, in _prep_field_computation(rr, sensors, bem, n_jobs, verbose)
753 cf = FIFF.FIFFV_COORD_HEAD
754 # multiply solution by "mults" here for simplicity
--> 755 solution = _bem_specify_coils(bem, coils, cf, mults, n_jobs)
756 else:
757 # Compute solution for EEG sensor
758 logger.info("Setting up for EEG...")
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/forward/_compute_forward.py:199, in _bem_specify_coils(bem, coils, coord_frame, mults, n_jobs)
179 """Set up for computing the solution at a set of MEG coils.
180
181 Parameters
(...)
196 MEG solution
197 """
198 # Make sure MEG coils are in MRI coordinate frame to match BEM coords
--> 199 coils, coord_frame = _check_coil_frame(coils, coord_frame, bem)
201 # leaving this in in case we want to easily add in the future
202 # if method != 'simple': # in ['ferguson', 'urankar']:
203 # raise NotImplementedError
(...)
207
208 # Process each of the surfaces
209 rmags, cosmags, ws, bins = _triage_coils(coils)
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/forward/_compute_forward.py:53, in _check_coil_frame(coils, coord_frame, bem)
50 if coord_frame != FIFF.FIFFV_COORD_MRI:
51 if coord_frame == FIFF.FIFFV_COORD_HEAD:
52 # Make a transformed duplicate
---> 53 coils, coord_frame = _dup_coil_set(coils, coord_frame, bem["head_mri_t"])
54 else:
55 raise RuntimeError(f"Bad coil coordinate frame {coord_frame}")
File ~/anaconda3/envs/mne_workshop/lib/python3.12/site-packages/mne/forward/_compute_forward.py:41, in _dup_coil_set(coils, coord_frame, t)
39 if key in coil:
40 coil[key] = apply_trans(t["trans"], coil[key], False)
---> 41 coil["r0"] = apply_trans(t["trans"], coil["r0"])
42 coil["rmag"] = apply_trans(t["trans"], coil["rmag"])
43 coil["cosmag"] = apply_trans(t["trans"], coil["cosmag"], False)
IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
Additional information
Platform macOS-15.5-x86_64-i386-64bit
Python 3.12.2 | packaged by conda-forge | (main, Feb 16 2024, 21:00:12) [Clang 16.0.6 ]
Executable /Users/mainak/anaconda3/envs/mne_workshop/bin/python3.12
CPU Apple M1
machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTSE64 MON DSCPL VMX EST TM2 SSSE3 CX16 TPR PDCM SSE4.1 SSE4.2 AES SEGLIM64
machdep.cpu.feature_bits: 151121000215084031
machdep.cpu.family: 6 (8 cores)
Memory 8.0 GiB
Core
├☑ mne 1.9.0 (latest release)
├☑ numpy 1.26.4 (OpenBLAS 0.3.27 with 8 threads)
├☑ scipy 1.14.0
└☑ matplotlib 3.8.4 (backend=MacOSX)
Numerical (optional)
├☑ sklearn 1.5.0
├☑ numba 0.59.1
├☑ nibabel 5.2.1
├☑ nilearn 0.10.4
├☑ dipy 1.9.0
├☑ openmeeg 2.5.11
├☑ pandas 2.2.2
├☑ h5io 0.2.3
├☑ h5py 3.11.0
└☐ unavailable cupy
Visualization (optional)
├☑ pyvista 0.43.10 (OpenGL 4.1 Metal - 89.4 via Apple M1)
├☑ pyvistaqt 0.11.1
├☑ vtk 9.2.6
├☑ qtpy 2.4.1 (PyQt5=5.15.8)
├☑ ipympl 0.9.4
├☑ pyqtgraph 0.13.7
├☑ mne-qt-browser 0.6.3
├☑ ipywidgets 8.1.3
├☑ trame_client 3.2.0
├☑ trame_server 3.0.2
├☑ trame_vtk 2.8.9
└☑ trame_vuetify 2.6.0
Ecosystem (optional)
├☑ eeglabio 0.0.2-4
├☑ edfio 0.4.3
├☑ mffpy 0.9.0
├☑ pybv 0.7.5
└☐ unavailable mne-bids, mne-nirs, mne-features, mne-connectivity, mne-icalabel, mne-bids-pipeline, neo
Description of the problem
I get a bug deep in the forward code when trying to simulate raw data with head movement.
Steps to reproduce
Link to data
No response
Expected results
No error and
rawdataActual results
Additional information
Platform macOS-15.5-x86_64-i386-64bit
Python 3.12.2 | packaged by conda-forge | (main, Feb 16 2024, 21:00:12) [Clang 16.0.6 ]
Executable /Users/mainak/anaconda3/envs/mne_workshop/bin/python3.12
CPU Apple M1
machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTSE64 MON DSCPL VMX EST TM2 SSSE3 CX16 TPR PDCM SSE4.1 SSE4.2 AES SEGLIM64
machdep.cpu.feature_bits: 151121000215084031
machdep.cpu.family: 6 (8 cores)
Memory 8.0 GiB
Core
├☑ mne 1.9.0 (latest release)
├☑ numpy 1.26.4 (OpenBLAS 0.3.27 with 8 threads)
├☑ scipy 1.14.0
└☑ matplotlib 3.8.4 (backend=MacOSX)
Numerical (optional)
├☑ sklearn 1.5.0
├☑ numba 0.59.1
├☑ nibabel 5.2.1
├☑ nilearn 0.10.4
├☑ dipy 1.9.0
├☑ openmeeg 2.5.11
├☑ pandas 2.2.2
├☑ h5io 0.2.3
├☑ h5py 3.11.0
└☐ unavailable cupy
Visualization (optional)
├☑ pyvista 0.43.10 (OpenGL 4.1 Metal - 89.4 via Apple M1)
├☑ pyvistaqt 0.11.1
├☑ vtk 9.2.6
├☑ qtpy 2.4.1 (PyQt5=5.15.8)
├☑ ipympl 0.9.4
├☑ pyqtgraph 0.13.7
├☑ mne-qt-browser 0.6.3
├☑ ipywidgets 8.1.3
├☑ trame_client 3.2.0
├☑ trame_server 3.0.2
├☑ trame_vtk 2.8.9
└☑ trame_vuetify 2.6.0
Ecosystem (optional)
├☑ eeglabio 0.0.2-4
├☑ edfio 0.4.3
├☑ mffpy 0.9.0
├☑ pybv 0.7.5
└☐ unavailable mne-bids, mne-nirs, mne-features, mne-connectivity, mne-icalabel, mne-bids-pipeline, neo