Repository: mne-tools/mne-python

Issue:
mne.beamformer.make_lcmv crashes when given a Label
`mne.beamformer.make_lcmv` works without any label chosen but crashes when a Label instance is chosen with the `label=` argument.

Please help! Thank you :slight_smile:

OS details:
MNE version: 1.3.0
operating system: Ubuntu 20.04

Minimally reproducible example:

```
import matplotlib.pyplot as plt
import mne
from mne.datasets import sample, fetch_fsaverage
from mne.beamformer import make_lcmv, apply_lcmv

data_path = sample.data_path()
subjects_dir = data_path / "subjects"
meg_path = data_path / "MEG" / "sample"
raw_fname = meg_path / "sample_audvis_filt-0-40_raw.fif"

# Read the raw data
raw = mne.io.read_raw_fif(raw_fname)
raw.info["bads"] = ["MEG 2443"]  # bad MEG channel

# Set up the epoching
event_id = 1  # those are the trials with left-ear auditory stimuli
tmin, tmax = -0.2, 0.5
events = mne.find_events(raw)

# pick relevant channels
raw.pick(["meg", "eog"])  # pick channels of interest

# Create epochs
proj = False  # already applied
epochs = mne.Epochs(
    raw,
    events,
    event_id,
    tmin,
    tmax,
    baseline=(None, 0),
    preload=True,
    proj=proj,
    reject=dict(grad=4000e-13, mag=4e-12, eog=150e-6),
)

# for speed purposes, cut to a window of interest
evoked = epochs.average().crop(0.05, 0.15)

# Visualize averaged sensor space data
evoked.plot_joint()

del raw  # save memory

data_cov = mne.compute_covariance(epochs, tmin=0.01, tmax=0.25, method="empirical")
noise_cov = mne.compute_covariance(epochs, tmin=tmin, tmax=0, method="empirical")
data_cov.plot(epochs.info)
del epochs

fwd_fname = meg_path / "sample_audvis-meg-vol-7-fwd.fif"
forward = mne.read_forward_solution(fwd_fname)

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
roi_names = [# Left
             'rostralanteriorcingulate-lh', # Left Rostral ACC
             'caudalanteriorcingulate-lh', # Left Caudal ACC
             'postcentral-lh', # Left S1,
             'insula-lh', 'superiorfrontal-lh', # Left Insula, Left DL-PFC,
             'medialorbitofrontal-lh', # Left Medial-PFC
             # Right
             'rostralanteriorcingulate-rh', # Right Rostral ACC
             'caudalanteriorcingulate-rh', # Right Caudal ACC
             'postcentral-rh', # , Right S1
             'insula-rh', 'superiorfrontal-rh', # Right Insula, Right DL-PFC
             'medialorbitofrontal-rh'] # Right Medial-PFC

subject="sample"
selected_labels = [mne.read_labels_from_annot(subject, regexp=roi, subjects_dir=subjects_dir)[0] for roi in roi_names]
print(selected_labels)

filters = make_lcmv(
    evoked.info,
    forward,
    data_cov,
    reg=0.05,
    noise_cov=noise_cov,
    label=selected_labels[0], # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    pick_ori="max-power",
    weight_norm="unit-noise-gain",
    rank=None,
)
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
```


Discussion:
Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴

I haven't tested the code but it looks okay, so if there is an error then we do probably have some bug. Hopefully someone can take a look soon!
@wmvanvliet or @britta-wstnr do you have time to look?

Hey - sorry this week is a sea of deadlines for me, but I will put it on my agenda for next week (unless @wmvanvliet beats me to it!) 📆 
Managed to check this out - note that you are using a volume forward model. The code runs fine for me with a surface model (`sample_audvis-meg-oct-6-fwd.fif`).

We might want to throw a better error message though, WDYT @larsoner ? right now it crashes with `TypeError: cannot unpack non-iterable Exception object`.
Sounds like we need to fix the exception handling (that unpacking error suggests we're doing something wrong) and indeed add an error message if a label is requested for a volume source space
Hi Britta and team,

Thank you for getting to the bottom of it!

I used a volume forward model based on the recommendation from the LCMV tutorial. Assuming I keep the volume forward model, could I compute the STC with LCMV for the entire brain first, and then extract the data for just one label then? Or is that still exclusive to the surface model,

Thanks again,
George
On Jun 2, 2023 at 7:54 AM -0400, Britta Westner ***@***.***>, wrote:
> Managed to check this out - note that you are using a volume forward model. The code runs fine for me with a surface model (sample_audvis-meg-oct-6-fwd.fif).
> We might want to throw a better error message though, WDYT @larsoner ? right now it crashes with TypeError: cannot unpack non-iterable Exception object.
> —
> Reply to this email directly, view it on GitHub, or unsubscribe.
> You are receiving this because you authored the thread.Message ID: ***@***.***>

[extract_label_time_course](https://mne.tools/stable/generated/mne.extract_label_time_course.html) can work with volume atlases, so maybe you can calculate LCMV for the whole brain and then extract that way

Resolving patch:
diff --git a/mne/source_space.py b/mne/source_space.py
--- a/mne/source_space.py
+++ b/mne/source_space.py
@@ -1208,7 +1208,10 @@ def label_src_vertno_sel(label, src):
         Indices of the selected vertices in sourse space.
     """
     if src[0]["type"] != "surf":
-        return Exception("Labels are only supported with surface source " "spaces")
+        raise ValueError(
+            "Labels are only supported with surface source spaces, "
+            f"got {_src_kind_dict[src[0]['type']]} source space"
+        )
 
     vertno = [src[0]["vertno"], src[1]["vertno"]]
 


Test patch:
diff --git a/mne/beamformer/tests/test_lcmv.py b/mne/beamformer/tests/test_lcmv.py
--- a/mne/beamformer/tests/test_lcmv.py
+++ b/mne/beamformer/tests/test_lcmv.py
@@ -293,6 +293,15 @@ def test_make_lcmv_bem(tmp_path, reg, proj, kind):
     stc = apply_lcmv(evoked, filters)
     stc.crop(0.02, None)
 
+    # Smoke test for label= support for surfaces only
+    label = mne.read_label(fname_label)
+    if kind == "volume":
+        ctx = pytest.raises(ValueError, match="volume source space")
+    else:
+        ctx = nullcontext()
+    with ctx:
+        make_lcmv(evoked.info, fwd, data_cov, reg=reg, noise_cov=noise_cov, label=label)
+
     stc_pow = np.sum(np.abs(stc.data), axis=1)
     idx = np.argmax(stc_pow)
     max_stc = stc.data[idx]