Skip to content

Use `fwd["info"]["dev_head_t"] when raw.info["dev_head_t"] is None? #13604

Description

@OleBialas

Describe the new feature or enhancement

I tried to simulate EEG data using a forward model:

raw_fname = mne.datasets.eegbci.load_data(subjects=1, runs=[6])[0]
raw = mne.io.read_raw_edf(raw_fname, preload=True)
montage = mne.channels.make_standard_montage("standard_1005")
mne.datasets.eegbci.standardize(raw)
raw.set_montage(montage);
fs_dir = mne.datasets.fetch_fsaverage(verbose=True)
src = fs_dir / "bem" / "fsaverage-ico-5-src.fif"
bem = fs_dir / "bem" / "fsaverage-5120-5120-5120-bem-sol.fif"
fwd = mne.make_forward_solution(
    raw.info, trans="fsaverage", src=src, bem=bem, eeg=True, mindist=5.0, n_jobs=None
)

labels = mne.read_labels_from_annot('fsaverage', parc='aparc', subjects_dir=fs_dir.parent)
label_names = ["transversetemporal-lh", "transversetemporal-rh"]
labels = [l for l in labels if l.name in label_names]

times = np.arange(0, 1, 1/raw.info["sfreq"])
stc = mne.simulation.simulate_sparse_stc(
    fwd["src"],
    n_dipoles=2,
    times=times,
    labels=labels
)
n_epochs = 10
raw_sim = mne.simulation.simulate_raw(raw.info, [stc] * n_epochs, forward=fwd, verbose=False)

However, this gave me the error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[32], line 1
----> 1 raw_sim = mne.simulation.simulate_raw(raw.info, [stc] * n_epochs, forward=fwd, verbose=False)

File <decorator-gen-429>:10, in simulate_raw(info, stc, trans, src, bem, head_pos, mindist, interp, n_jobs, use_cps, forward, first_samp, max_iter, verbose)

File ~/projects/iBOTS-Intro-to-EEG-MEG-Analysis-with-MNE-Python/.pixi/envs/default/lib/python3.13/site-packages/mne/simulation/raw.py:295, in simulate_raw(info, stc, trans, src, bem, head_pos, mindist, interp, n_jobs, use_cps, forward, first_samp, max_iter, verbose)
    288 if any(x is not None for x in (trans, src, bem, head_pos)):
    289     raise ValueError(
    290         "If forward is not None then trans, src, bem, "
    291         "and head_pos must all be None"
    292     )
    293 if not np.allclose(
    294     forward["info"]["dev_head_t"]["trans"],
--> 295     info["dev_head_t"]["trans"],
    296     atol=1e-6,
    297 ):
    298     raise ValueError(
    299         "The forward meg<->head transform "
    300         'forward["info"]["dev_head_t"] does not match '
    301         'the one in raw.info["dev_head_t"]'
    302     )
    303 src = forward["src"]

TypeError: 'NoneType' object is not subscriptable

I could fix it by copying the "dev_head_t" from fwd:

raw.info["dev_head_t"] = fwd["info"]["dev_head_t"]

However, this feels kind of hacky.
Is there a reason why copying the transform from fwd is not the default behavior when raw.info["dev_head_t"] is None?

Describe your proposed implementation

In simulate raw, copy fwd["info"]["dev_head_t"] when raw.info["dev_head_t"] is None.

Describe possible alternatives

If there are reasons why copying the transform is a bad idea, at least print a more explicit error message that mentions the missing transform in raw.info

Additional context

No response

Activity

  1. larsoner commented on Jan 22, 2026

    @larsoner
    Member

    In general, assuming fwd["info"]["dev_head_t"] is correct when raw.info["dev_head_t"] is None would be dangerous I think. Better for a user to explicitly set it. But for your particular case, if this fails:

    raw_fname = mne.datasets.eegbci.load_data(subjects=1, runs=[6])[0]
    raw = mne.io.read_raw_edf(raw_fname, preload=True)
    assert raw.info["dev_head_t"] is None
    

    then there is something bad happening with read_raw_edf (it only ever reads EEG data so dev_head_t should be None, and hopefully was done in #13112). And if that's the case then you should also have

    assert fwd["info"]["dev_head_t"] is None
    

    Which of these fails?

  2. added and removed on Jan 22, 2026
  3. OleBialas commented on Jan 22, 2026

    @OleBialas
    Author

    Thanks for the quick response!
    I ran this code

    import mne
    
    raw_fname = mne.datasets.eegbci.load_data(subjects=1, runs=[6])[0]
    raw = mne.io.read_raw_edf(raw_fname, preload=True)
    montage = mne.channels.make_standard_montage("standard_1005")
    mne.datasets.eegbci.standardize(raw)
    raw.set_montage(montage)
    fs_dir = mne.datasets.fetch_fsaverage(verbose=True)
    src = fs_dir / "bem" / "fsaverage-ico-5-src.fif"
    bem = fs_dir / "bem" / "fsaverage-5120-5120-5120-bem-sol.fif"
    fwd = mne.make_forward_solution(
        raw.info,
        trans="fsaverage",
        src=src,
        bem=bem,
        meg=False,
        eeg=True,
        mindist=5.0,
        n_jobs=None,
    )
    assert raw.info["dev_head_t"] is None
    assert fwd["info"]["dev_head_t"] is None

    and got an error on the second assertion

        assert fwd["info"]["dev_head_t"] is None
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AssertionError

    Using MNE 1.11.0

  4. larsoner commented on Jan 22, 2026

    @larsoner
    Member

    Okay, good to know... I suspect this is a bug with our forward code that it adds a non-None dev_head_t

  5. drammock commented on Jan 22, 2026

    @drammock
    Member

    trans="fsaverage"

    isn't this the culprit?

  6. larsoner commented on Jan 22, 2026

    @larsoner
    Member

    That should set the head<->MRI (head_mri_t) trans, not the MEG<->head trans (dev_head_t)

  7. added this to the 1.12 milestone on Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions