Error: Compensation grade of ICA (3) and Raw (0) do not match

  • MNE version: 1.11.0
  • operating system: WSL: Ubuntu-22.04

Hi everyone!

I’m a young researcher very new to MEG analysis and MNE… looking for some help :blush:

I’m currently adapting an MEG pre-processing pipeline written in Neuropycon to MNE-BIDS-Pipeline.

I’m working with already BIDSified CTF resting state data, but I had to BIDSify emptyroom recordings for the pipeline to correctly retrieve them: following BIDS guidelines and what I found on this forum, I stored the .ds data in sub-emptyroom with sessions in the format ses-YYYYMMDD, also updating the AssociatedEmptyRoom field in the sidecar .json.

Up until now I proceeded searching for the best matching configuration options that could allow me to replicate (I admit, almost blindly) my reference pipeline via the config file.

Now I’m stuck on this error (in the preprocessing/_08a_apply_ica step) that is somehow out of my comprehension:

│10:07:22│ ❌ sub-063 ses-01 run-noise A critical error occurred. The error message was: Compensation grade of ICA (3) and Raw (0) do not match

Aborting pipeline run. The traceback is:

File “/home/leozm/CRNL_projects/envs/MNEBIDS_mimosa_env/lib/python3.10/site-packages/mne_bids_pipeline/steps/preprocessing/_08a_apply_ica.py”, line 213, in apply_ica_raw
ica.apply(raw)
File “”, line 12, in apply
File “/home/leozm/CRNL_projects/envs/MNEBIDS_mimosa_env/lib/python3.10/site-packages/mne/preprocessing/ica.py”, line 2255, in apply
_check_compensation_grade(
File “/home/leozm/CRNL_projects/envs/MNEBIDS_mimosa_env/lib/python3.10/site-packages/mne/utils/check.py”, line 381, in _check_compensation_grade
raise RuntimeError(

As far as I understood, during ICA the experimental data is compared to emptyroom and given that they have different compensation grades the error occurs.

I’m using emptyroom in order to calculate the noise covariance matrix for the inverse problem, but talking with some colleagues seems that for CTF that is useless (?).

Anyway I ask you help for understanding what’s going on and orient myself better :slight_smile: .

This is my config.py for the moment:

sessions = ["01"]

task = 'rest'

task_is_rest = True

runs = ["01"]

subjects = ["063"]

process_empty_room = True

# QUESTION: I initially set ch_types = ["meg"], but then during preprocessing/_06a1_fit_ica the "grad" key in ica_reject caused this error:
# No GRAD channel found. Cannot reject based on GRAD.
# Why this??
ch_types = ["mag", "grad"]

data_type = "meg"

random_state = 42

l_freq = 0.1

h_freq = 150

raw_resample_sfreq = 300

epochs_tmin = 0.0

rest_epochs_duration = 2.0

rest_epochs_overlap = 0.0

spatial_filter = "ica"

ica_reject = {

            "mag": 5e-12,

            "grad": 5000e-13

            }

ica_algorithm = "fastica"

ica_l_freq = 1.0

ica_max_iterations = 1000

ica_n_components = 0.95

run_source_estimation = True

inverse_method = "MNE"

noise_cov = "emptyroom"

noise_cov_method = "empirical"

Thanks a lot for any advice!!!

Hi @LeonardoMelloni and welcome to the forum!

@larsoner, should we call Raw.apply_gradient_compensation() somewhere?

Richard

I don’t think we (as in MNE-Python) should… I think the user probably should before trying to apply ICA. Maybe we need to improve the error message here

@larsoner But this is in MNE-BIDS-Pipeline. So either we should handle this automatically, or it’s something that should be taken care of when converting the data to BIDS, don’t you think?

Thanks for your replies guys, they allowed me to better understand the issue.

Now I’ll try to use mne.io.Raw.apply_gradient_compensation() during BIDSification and see how it goes.

Anyway, are you considering to implement it in the pipeline?

Hi! I’m still not sure what the right approach is here, honestly. It appears the BIDS specification currently doesn’t cover this. Hence, I would assume it’d be better to apply the compensation before converting to BIDS.

@sappelhoff, perhaps this should even live in MNE-BIDS?

Yeah it’s weird to me that they don’t all have the same compensation grade. But probably something that MNE-BIDS-Pipeline could easily handle with a new gradient_compensation: int | None = None . @LeonardoMelloni want to try adding it to MNE-BIDS-Pipeline and opening a PR?

Or if you want, I could try opening a PR and you could test it on your data.

  • I don’t think I have the necessary programming skills to do the pull request properly and in a reasonable amount of time (right now I am doing an internship and cannot afford to spend too much time on this kind of issues unfortunately).

  • I’m considering to first correct for it in the BIDSification as you suggested and if I’ll see that there’s no other solution I’ll try to modify the pipeline code.

    • now, considering to do it in the BIDSification, is it okay to use mne.io.Raw.apply_gradient_compensation() without making a copy of the data,considering that the function works in-place?I’m referring to what is done in this tutorial https://mne.tools/stable/auto_tutorials/inverse/85_brainstorm_phantom_ctf.html

    • In which direction should mne.io.Raw.apply_gradient_compensation() be applied? Experimental from 3 to 0 (but I would loose the compensation during the recording) or emptyroom from 0 to 3 (but then why using emptyroom)?

  • can you signal me some reference or someone using the MNE-BIDS pipeline for CTF data…I’m really struggling to find some topics on this

  • I couldn’t find online a documentation that could motivate the decision to apply ICA to emptyroom recording. In the forum it seems more a technical decision in order to make sure that all data (both noise and experimental) are homogeneous for subsequent analysis, including source reconstruction. But most of the topics I read were referring mainly to maxwell filtering which, as far as I understood, is not strictly concerning or needed for CTF data

I’m working on making a script for “re-BIDSifying” the data imposing the compensation grade to 0 for experimental data. Now I’m running into a strange behavior that I think can be summed up with the following MWE:

from pathlib import Path

import mne

from mne_bids import (

    BIDSPath,

    read_raw_bids,

    write_raw_bids

)




old_bids_root = Path("/home/.../BIDS")

new_bids_root = Path("/home/.../BIDS_for_MNE-BIDS-Pipeline")

target_grade = 0

bp = BIDSPath(

    root=old_bids_root,

    subject="063",

    session="01",

    task="rest",

    run="01",

    datatype="meg"

)

raw = read_raw_bids(bids_path=bp, verbose=False)

print(f"Initial compensation grade: {raw.compensation_grade}")

raw.apply_gradient_compensation(target_grade)

new_bp = bp.copy().update(root=new_bids_root)

write_raw_bids(

        raw,

        bids_path=new_bp,

        overwrite=True,

        verbose=False

    )

new_raw = mne.io.read_raw_ctf(new_bp.fpath, preload=False)

print(f" → written {new_bp.fpath} with compensation grade {new_raw.compensation_grade}")

(NOTE: I created a new bids_path to go around the issue signalled here )

But strangely the compensation grade of the new raw is still 3:

Initial compensation grade: 3
Compensator constructed to change 3 → 0
...
Current compensation grade : 3
→ written /home/.../BIDS_for_MNE-BIDS-Pipeline/sub-063/ses-01/meg/sub-063_ses-01_task-rest_run-01_meg.ds with compensation grade 3

In the sidecar json:

"SoftwareFilters": {

        "SpatialCompensation": {

            "GradientOrder": 0

        }

    }

Why this happens? I saw I could impose in write_raw_bids to have format = ‘FIF’ and that would solve the issue, but I would prefer to keep .ds

Hmm I’m not sure about how it writes data… I doubt MNE-BIDS is smart enough to be able to write a different compensation grade :frowning:

I don’t think the modifications for MNE-BIDS-Pipeline will be too bad actually. Can you open a quick issue on GitHub · Where software is built so I don’t forget to try to fix it next week? It can be just a couple sentences linking to this discussion

Done. Thank you.

I went over the problem by changing the compensation grade of emptyroom from 0 to 3 during BIDSification and writing it back imposing format=’FIF’ to make everything work fine.

Anyway I got an other error during ICA on emptyroom because it had a different number of EEG channels with respect to experimental data. I simply used drop_channels to exclude all EEG, given that we are interested only in MEG.

  • why EEG channels were initially taken into account even if I set ch_types = [‘meg’]?
  • why is ICA applied to emptyroom?

They shouldn’t have been, this seems like a bug. I have a vague recollection of hitting something similar in the past months and fixing it, are you on latest mne-bids-pipeline main? If not, can you try it to see if this is fixed?

Typically whatever processing you apply to your task/rest data, you apply as similarly as possible to your empty room data. That way if you compute an empty room covariance or anything from it, the task/rest and empty room data remain comparable.

This seems to be working. But with the new version I’m running into new problems. I thought could be worth to open a new topic