Skip to content

Preflight cbendercheck dev - #13

Open
adamfreedman wants to merge 3 commits into
mainfrom
preflight_cbendercheck_dev
Open

Preflight cbendercheck dev#13
adamfreedman wants to merge 3 commits into
mainfrom
preflight_cbendercheck_dev

Conversation

@adamfreedman

Copy link
Copy Markdown
Contributor

Summary

Adds preflight quality/integrity gates and an adaptive CellBender re-run to the preprocessing workflow. The goal is to catch unusable inputs before the DAG launches, and to automatically react to a poor CellBender training curve rather than silently keeping a bad fit. Three self-contained additions, each with tests; no changes to existing resource requests or default behavior for healthy samples.

1. Preflight cell-count gate

A parse-time check counts called cells in each sample's CellRanger filtered_feature_bc_matrix (barcodes line count — no matrix load) and handles samples with too few cells to cluster before any job launches, governed by a new preflight_mode:

  • skip (default) — drop the sample from the DAG and report it; re-checked every run, so a re-sequenced sample with more cells is picked up automatically
  • error — hard-stop the run · warn — report only · off — disable

Only the CellRanger filtered count is knowable preflight (emptyDrops / cellbender_fromraw call cells at runtime), so it gates on that as the whole-sample viability signal. The runtime min-cells guard and the results/low_quality_samples/ quarantine remain the backstop for the other arms.

2. CellBender raw-matrix preflight

For the cellbender_fromraw arm, before any job launches (reads only the MTX header):

  • Hard error on a raw matrix.mtx that is unreadable, empty/degenerate (zero features/barcodes/nonzeros), or has fewer barcodes than the sample's filtered matrix (raw must be a superset) — a broken/wrong input to fix or exclude.
  • Warning (non-blocking) when raw droplets are < 2× the CellRanger-filtered cell count — too few empties for CellBender's ambient estimate, often a sign a filtered matrix was placed on the raw path.

These are input-integrity checks, so unlike the cell-count gate they are not governed by preflight_mode. Runs only when cellbender_fromraw is configured.

3. Adaptive CellBender re-run

After the initial CellBender run, the HTML report's automated assessment is parsed:

  • "learning curve looks normal" → keep the initial run.
  • "re-run with half the current learning rate" → if cellbender_adaptive_rerun is on, re-run at half cellbender_learning_rate and keep the re-run only if its curve is normal; otherwise fall back to the initial run.
  • Any unrecognized assessment → hard error, so report-parsing edge cases surface rather than passing silently.

Both runs' reports are archived (_report_initial.html / _report_rerun.html) and a per-sample status file records the outcome. A new cellbender_adaptive_summary rule aggregates every sample into results/cellbender/cellbender_adaptive_summary.tsv, reporting which samples needed a re-run and whether it resolved the learning curve.

New config keys (validated, with documented defaults)

preflight_min_cells: 100
preflight_mode: "skip"             # skip | error | warn | off
cellbender_learning_rate: 0.0001   # CellBender's default; re-run uses exactly half
cellbender_adaptive_rerun: true    # false = always keep the single initial run

New outputs

  • results/cellbender/cellbender_{sample}_report.html + archived _report_initial.html / _report_rerun.html
  • results/cellbender/cellbender_{sample}_adaptive_status.txt (per-sample outcome)
  • results/cellbender/cellbender_adaptive_summary.tsv (run-level rollup)

Tests

New/updated coverage (+965 / −44 across 12 files): assess_report unit tests (normal / rerun / unknown), every adaptive orchestration branch via a fake CellBender, the run-level summary, the raw-matrix preflight (4 cases + minimal-datadir fixture), the cell-count gate (skip/error/warn/off/pass), and the new config-validation cases.

Compatibility

No change to the CellBender SLURM request (48 h GPU walltime, runtime = 2880) versus main — the adaptive wrapper runs both passes inside the same job, so the existing walltime covers a re-run. Behavior for healthy samples is unchanged; all new gates either no-op (preflight_mode: skip only affects low-cell samples) or default to CellBender's own settings.

adamfreedman and others added 3 commits August 24, 2026 10:22
A parse-time check counts called cells in each sample's CellRanger filtered_feature_bc_matrix (barcodes.tsv line count, no matrix load) and, per preflight_mode, skips (default) / errors / warns on samples below preflight_min_cells (default 100) before any job launches. Only the CellRanger filtered count is knowable preflight (emptydrops/cellbender_fromraw call cells at runtime), so it gates on that as the whole-sample viability signal; require_min_cells_for_pca + the low_quality_samples quarantine remain the runtime backstop for the other arms. 'skip' is dynamic (re-checked each run, so a re-sequenced sample returns automatically). common.smk: count_filtered_cells, preflight_min_cells_check, config validation; Snakefile: gate after excluded_samples; config.yaml: documented defaults; tests: test_preflight_checks.py (skip/error/warn/off/pass) + 2 config-validation cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ency warning)

For the cellbender_fromraw arm, before any job launches: hard-error on a raw matrix.mtx that is unreadable, empty/degenerate (zero features/barcodes/nonzeros), or has fewer barcodes than the sample's filtered matrix (raw must be a superset) -- a broken/wrong input to fix or exclude; and warn (non-blocking) when raw droplets are < 2x the CellRanger-filtered cell count (too few empties for CellBender's ambient estimate, often a filtered matrix on the raw path). These are input-integrity checks, so unlike the cell-count gate they are NOT governed by preflight_mode. Runs only when cellbender_fromraw is configured; reads only the MTX header. common.smk: read_mtx_dims, cellbender_preflight_checks; Snakefile: gate after the cell-count preflight; tests: 4 cases + a minimal-datadir fixture.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ssessment

After the initial CellBender run, parse the HTML report's automated assessment:
- "learning curve looks normal" -> keep the initial run.
- "re-run with half the current learning rate" -> if cellbender_adaptive_rerun
  is on, re-run at half cellbender_learning_rate and keep the re-run only if ITS
  curve is normal, otherwise fall back to the initial run.
- Any unrecognized assessment is a hard error so report-parsing edge cases surface.

Both runs' reports are archived (_report_initial.html / _report_rerun.html) and a
per-sample status file records the outcome. A new cellbender_adaptive_summary rule
aggregates every sample's status into results/cellbender/cellbender_adaptive_summary.tsv,
reporting which samples needed a re-run and whether it resolved the learning curve.

New config keys (validated): cellbender_learning_rate (default 0.0001, CellBender's
default) and cellbender_adaptive_rerun (default true). The wrapper's assess_report is a
pure function; tests cover it plus every orchestration branch (via a fake cellbender),
the run-level summary, and the two new config-validation cases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant