Skip to content

Fix emptyroom proc clean#6

Closed
mrribbits wants to merge 16 commits intoharrisonritz:mainfrom
mrribbits:fix-emptyroom-proc-clean
Closed

Fix emptyroom proc clean#6
mrribbits wants to merge 16 commits intoharrisonritz:mainfrom
mrribbits:fix-emptyroom-proc-clean

Conversation

@mrribbits
Copy link
Copy Markdown
Collaborator

mne_bids_pipeline does not appear to auto-create a proc-clean empty-room file after filtering (ICA is not applied to empty-room data), but make_cov requires it.

So now it just makes a copy of proc-filt named proc-clean.

harrisonritz and others added 16 commits February 22, 2026 18:01
This commit introduces a new test suite for the decoding functions in `run_decoding.py`. The tests cover various components including the `MultivariateNoiseNormalizer`, contrast preparation, pipeline factories, and decoding functions. Additionally, it includes tests for saving results and plotting functions, ensuring that all functionalities work as expected without requiring actual BIDS data files. Synthetic MNE objects are utilized to facilitate testing.
- Replaced calls to `mne_bids.write_raw_bids` with `write_raw_bids_preserve_events` in multiple analysis classes (BadChannels, BadSegments, ManualChannel, RegressReference, ZCAFilter) to ensure event integrity during BIDS writing.
- Updated unit tests to mock `write_raw_bids_preserve_events` instead of `mne_bids.write_raw_bids`, verifying that event counts remain stable and that events.tsv files are unchanged after rewrites.
- Added comprehensive tests for event alignment and preservation, addressing potential issues with event count mismatches during preprocessing.
… artifact detection

Two new ICA diagnostic metrics are added to _ica_component_diagnostics():

1. spectral_deriv_kurtosis: kurtosis of d(log_psd)/df computed over all
   Welch frequencies. A boxcar-like artifact (sharp onset + offset edges)
   produces a heavy-tailed derivative distribution → high kurtosis.
   Natural 1/f spectra are smooth → low/near-zero kurtosis.

2. spectral_resid_kurtosis: kurtosis of the residuals from the power-law
   (spectral slope) fit in [fmin, fmax]. A narrow-band artifact creates a
   concentrated bump above the 1/f baseline → heavy-tailed residuals →
   high kurtosis. Reuses the existing lstsq computation.

Both are added to _prepare_metrics_for_gesd() with signed-sqrt transform
(consistent with other kurtosis metrics) and outlier_side=1 (high = bad).
This raises the total number of GESD metrics from 5 to 7.

Tests updated: expected_keys, sample_diagnostics fixture, metric count
(5 → 7), name/direction assertions, and a new targeted test verifying
that a synthetic pure-tone component scores higher on both metrics than
a broadband 1/f-like component.

https://claude.ai/code/session_01MYY6LzmHA4qy45TCHoWs8E
Adds _label_by_corrmap() to AutoICAAnalysis, gated by corrmap_bads=False
(opt-in, since it requires a pre-built template directory).

Design
------
Templates are stored as .npy topography arrays (one per file) in a
user-specified directory (corrmap_template_dir).  A companion file
reference_channels.npy lists the channel names the templates were
defined on.  On each run the template is aligned to the current ICA's
channel order: reference values are looked up by channel name, and any
ICA channel absent from the reference receives a weight of 0 so it
does not influence the correlation.

Config parameters
-----------------
  corrmap_bads          bool    master switch (default False)
  corrmap_template_dir  str     path to template directory
  corrmap_eog           bool    use eog_*.npy templates (default True)
  corrmap_ecg           bool    use ecg_*.npy templates (default True)
  n_eog_templates       int     how many EOG templates to use (default 3)
  n_ecg_templates       int     how many ECG templates to use (default 3)
  corrmap_threshold     float | 'auto'  passed to corrmap (default 'auto')

Behaviour
---------
- Loops over up to n_{type}_templates files in alphabetical order.
- Each corrmap call uses mne.preprocessing.corrmap with plot=False.
- Matches from successive templates are unioned (corrmap overwrites
  ica.labels_ per call, so we accumulate manually).
- Matched components go into ica.labels_['eog'/'ecg'] AND ica.exclude.
- All failure modes (missing dir, missing reference file, no template
  files, corrmap exception) log and skip gracefully.

Tests
-----
TestLabelByCorrmap covers: all graceful-skip paths, EOG/ECG detection
with exact-topography templates, label↔exclude consistency, accumulation
across multiple templates, channel-subset alignment (reference wider than
ICA), n_templates limiting, and integration via _auto_ica().

https://claude.ai/code/session_01MYY6LzmHA4qy45TCHoWs8E
All seven corrmap-related config parameters now follow the same
underscore-prefix convention as other custom pipeline flags
(e.g. _auto_ica, _do_HFC):

  corrmap_bads          → _corrmap_bads
  corrmap_template_dir  → _corrmap_template_dir
  corrmap_eog           → _corrmap_eog
  corrmap_ecg           → _corrmap_ecg
  n_eog_templates       → _n_eog_templates
  n_ecg_templates       → _n_ecg_templates
  corrmap_threshold     → _corrmap_threshold

Updated in auto_ica.py (getattr calls, docstrings, log messages)
and test_auto_ica.py (fixture assignments, docstrings, comments).

https://claude.ai/code/session_01MYY6LzmHA4qy45TCHoWs8E
Remove _corrmap_eog and _corrmap_ecg boolean flags. Whether EOG or ECG
template matching runs is now controlled entirely by the template count:

  _n_eog_templates = 0  →  skip EOG matching
  _n_ecg_templates = 0  →  skip ECG matching

The type_configs block in _label_by_corrmap() is simplified to two
unconditional getattr calls that check count > 0. Docstrings and all
test fixtures updated to remove the removed flags.

https://claude.ai/code/session_01MYY6LzmHA4qy45TCHoWs8E
…al-derivative-metric-VCfYQ

Add spectral kurtosis metrics and corrmap template matching for ICA
…malizer and FlexPCA transformers for improved MEG decoding pipelines.
…der patterns

- All decoding outputs (TSV, NPZ, PNG/PDF figures) now land in a
  `decoding/` subfolder within the subject's meg derivatives folder,
  keeping the parent meg/ directory clean.

- All six save_*_results() functions gained an `out_dir` parameter;
  filenames are still derived from BIDSPath naming conventions but
  written to `decoding_dir` instead of the meg/ root.

- New `plot_subject_time_patterns()` function generates a
  `mne.EvokedArray.plot_joint()` figure for each contrast, mapping
  the already-computed sensor-space patterns back through the full
  pipeline via `get_coef(..., inverse_transform=True)`.  Topographic
  time points are controlled by the new `_decoder_pattern_times`
  config attribute (default None → MNE auto-picks).

- Pattern plots are produced for both within-condition time decoding
  (prefix `time_patterns_*`) and cross-condition time decoding
  (prefix `cross_time_patterns_*`).

- Tests updated: save function calls pass `tmp_path` as `out_dir`;
  two new smoke tests cover `plot_subject_time_patterns` including
  graceful handling when channel positions are absent.

https://claude.ai/code/session_013n2yHjrvm3dyT5fRzQbQjY
Introduces GridSearchCV over 4 log-spaced values of the LinearSVC
regularisation parameter C (default [0.001, 0.01, 0.1, 1]) inside each
outer LOGO fold of the epoch decoder.

Key changes
-----------
* run_subject_epoch_decoding() now runs a manual outer LOGO loop.
  For each fold it instantiates a fresh GridSearchCV wrapping
  _make_epoch_clf() with cv=LeaveOneGroupOut() as the inner CV.
  Fitting passes groups so the inner LOGO can respect run structure.
  Edge case: when the training fold has < 2 unique groups (e.g. only 2
  runs total), inner CV is skipped and C defaults to 1.

* Optimal C per fold is printed to the console together with the modal
  (most common) value across folds.

* Return dict gains best_C_per_fold (list) and epoch_C_grid (list).

* save_epoch_results() expands the TSV from one summary row to one
  row per outer fold, adding fold, fold_score, and best_C columns.

* plot_subject_epoch_bar() gains a second subplot (when best_C_per_fold
  is present): bar height = modal C, scatter = per-fold values on a log
  scale.  Each contrast gets one bar group.

* process_subject() reads _decoder_epoch_C_grid from config (default
  [0.001, 0.01, 0.1, 1]) and passes it to the epoch decoder.

Tests
-----
* Remove patches of the now-absent cross_val_score; tests run the
  actual (fast, small-data) function.
* Add assertions for best_C_per_fold length, grid membership, and the
  new C subplot smoke test (with and without best_C data).

https://claude.ai/code/session_013n2yHjrvm3dyT5fRzQbQjY
Copy link
Copy Markdown
Owner

@harrisonritz harrisonritz left a comment

Choose a reason for hiding this comment

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

can you make a PR on the dev branch instead, just to see if this is resolved?

The pipeline doesnt crash at make_cov sections IIUC -- is this an issue for custom code?
It would be helpful to see exactly where you are running into issues.

@mrribbits
Copy link
Copy Markdown
Collaborator Author

Not able to replicate this issue with current dev branch. Closing.

@mrribbits mrribbits closed this Apr 19, 2026
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.

3 participants