Skip to content

Deep source modeling (phase 1) - #14130

Open
payamsash wants to merge 11 commits into
mne-tools:mainfrom
payamsash:enh/subcortical-surface-source-space
Open

Deep source modeling (phase 1)#14130
payamsash wants to merge 11 commits into
mne-tools:mainfrom
payamsash:enh/subcortical-surface-source-space

Conversation

@payamsash

Copy link
Copy Markdown
Member

Reference issue (if any)

First phase of #14097, also see #6784

What does this implement/fix?

adds setup_subcortical_source_space which should/will support both label (aseg) and surface (e.g coming from CBM).

Additional information

This is just a Proof-of-concept with sample subject.

@payamsash
payamsash requested a review from larsoner as a code owner August 4, 2026 09:40
@payamsash

Copy link
Copy Markdown
Member Author

you can test it with this small code snippet:

import mne
from mne.datasets import sample

subjects_dir = sample.data_path() / "subjects"
subject = "sample"

# label
src_label = mne.setup_subcortical_source_space(
    subject, label=["Left-Hippocampus", "Left-Amygdala"], subjects_dir=subjects_dir
)
print(src_label.kind)

# surface (e.g for CBM)
surface = subjects_dir / subject / "surf" / "lh.white"
src_surface = mne.setup_subcortical_source_space(
    subject, surface=surface, subjects_dir=subjects_dir, keep_largest_component=False
)
print(src_surface.kind)

# cortex + subcortical
cortex_src = mne.setup_source_space(
    subject, spacing="oct4", add_dist=False, subjects_dir=subjects_dir, verbose=False
)
mixed = mne.SourceSpaces(list(cortex_src) + list(src_label))
print(mixed.kind)

# quick plot 
brain = mne.viz.Brain(
    subject,
    subjects_dir=subjects_dir,
    hemi="lh",
    surf="white",
    alpha=0.3,
    background="white",
    cortex="low_contrast",
)
brain.add_volume_labels(labels=["Left-Hippocampus", "Left-Amygdala"])

@ttaiv

ttaiv commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Thank you @payamsash! I ran you test code snippet using a cerebellar surface for sample from CMB and it worked well. I created a source space with cerebellum and cortex with mixed = src_surface + cortex_src and was able to plot it with mixed.plot().

Comment thread mne/_fiff/constants.py Outdated
FIFF.FIFFV_MNE_SURF_LEFT_HEMI = 101
FIFF.FIFFV_MNE_SURF_RIGHT_HEMI = 102
FIFF.FIFFV_MNE_SURF_MEG_HELMET = 201 # Use this irrespective of the system
FIFF.FIFFV_MNE_SURF_SUBCORTICAL_ID_BASE = 1000 # + aseg value, e.g. hippocampus

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, see this PR. I also added a temp one here: mne/_fiff/tests/test_constants.py

@payamsash

Copy link
Copy Markdown
Member Author

ready to be reviewed @drammock . Thanks in advance

@ttaiv

ttaiv commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Any updates on this @larsoner @drammock? The CMB package would greatly benefit from subcortical surface source space support.

@larsoner larsoner left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this API / direction, it looks workable. We should wait for @drammock though

FYI we plan to cut 1.13 in the next few days, I think we should merge this PR soon after that lands so we have a release cycle to properly integrate the necessary features and work out issues

@drammock drammock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach is OK for me. Can you add some basic tests? I'm thinking: label input, mesh input, and I/O roundtrip

Comment thread mne/source_space/_source_space.py Outdated
Comment on lines +2110 to +2115
This is a first, deliberately narrow proof of concept: it has been
validated interactively on the ``sample`` subject. Known gaps, to be
addressed in follow-up work: morphing (:class:`~mne.SourceMorph`) does
not yet support these source spaces, and
:func:`mne.extract_label_time_course` does not yet know how to select
vertices within a subcortical-surface label.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm 50/50 on whether this warning should go at the top of the docstring (just before Parameters section) rather than in the Notes section. Thoughts?

Suggested change
This is a first, deliberately narrow proof of concept: it has been
validated interactively on the ``sample`` subject. Known gaps, to be
addressed in follow-up work: morphing (:class:`~mne.SourceMorph`) does
not yet support these source spaces, and
:func:`mne.extract_label_time_course` does not yet know how to select
vertices within a subcortical-surface label.
.. warning::
This is **experimental** functionality. :class:`~mne.SourceSpaces` created by
this function are not (yet) compatible with morphing (:class:`~mne.SourceMorph`)
and :func:`mne.extract_label_time_course` does not yet know how to select
vertices within a subcortical-surface label.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the warning could very well go at the top. Could also maybe add that plotting support for these source spaces is limited (at least plot() method of resulting MixedSourceEstimate currently throws error)?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with both

:func:`mne.extract_label_time_course` does not yet know how to select
vertices within a subcortical-surface label.

.. versionadded:: 1.12

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@larsoner should this go in before 1.12 release, or just after? I'm OK with either, slightly lean toward after

Comment thread mne/source_space/_source_space.py Outdated
if keep_largest_component:
rr, tris = _keep_largest_component(rr, tris)
s = _surf_from_mesh(rr, tris, subject)
s["id"] = FIFF.FIFFV_MNE_SURF_SUBCORTICAL_ID_BASE

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, if the user passes a mesh (not a label) then the id is just the offset (SUBCORTICAL_ID_BASE), since we have no way of knowing what subcortical structure(s) the mesh represents. Are the seg_ids for volume labels always non-zero? In other words, if a source has id == 1000 then for certain we don't know what structure this is?

@payamsash payamsash Sep 3, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, for label-based source spaces the seg_id is always the nonzero FS aseg label value, so they can never be 1000. and yes with only given surface we can't say which structure it represents.

@drammock

drammock commented Sep 2, 2026

Copy link
Copy Markdown
Member

also maybe worth asking @johnsam7 and @jasmainak for opinions here.

@jasmainak

Copy link
Copy Markdown
Member

@payamsash and @ttaiv I would say try to run this branch to simplify CMB example script and then it will be trivial to merge this branch. Example script:

https://github.com/johnsam7/ceremegbellum/blob/main/examples/example_script.py

that way you'll discover what the API needs.

@ttaiv

ttaiv commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

@jasmainak Regarding the CMB example script, I think the effect of this PR is that calling cmb.setup_full_source_space is replaced with a call to mne.setup_subcortical_source_space and the concatenation of cortical and subcortical source space. Then future PRs should address delegating plotting for MNE (currently the resulting MixedSourceEstimate cannot be plotted with MNE)

Comment thread mne/_fiff/tests/test_constants.py Outdated
Comment on lines +60 to +63
_tag_ignore_names = (
# pending addition to fiff-constants, see mne-tools/mne-python#14130
"FIFFV_MNE_SURF_SUBCORTICAL_OFFSET",
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can remove this now; mne-tools/fiff-constants#47 is merged. You'll need to update the hash in mne/_fiff/tests/test_constants.py though (just below the imports at the top of the file)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants