|
| 1 | +# Handoff: 4-modality RegularizedMultimodalVI on Argelaguet mouse gastrulation |
| 2 | + |
| 3 | +**Status**: blocked on ATAC re-aggregation. Notebook + marker CSV + TSV all built, but cannot submit yet — the existing ATAC h5ad covers only 6/11 samples (the older 2021 build pre-dates additions to the dataset). User has decided to rebuild ATAC from fragments for all 11 samples, then intersect with the *existing* peak set by **genomic coordinate overlap** (not exact name match). |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +Train **4-modality `RegularizedMultimodalVI`** (RNA total + spliced + unspliced + ATAC) on the **Argelaguet mouse gastrulation multiome** (Pijuan-Sala / Marioni 2022). Submit a Phase-1B-style slurm sweep with **3 conditions**: `_balencode`, `_balencode_zloc50x`, `_balencode_burst`. |
| 10 | + |
| 11 | +Downstream use: per-sample UMAPs across the gastrulation stages, with cell-type overlays from the Briscoe-lab dorsoventral spinal-cord progenitor marker list (title-cased to mouse symbols). |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## Existing plan & approved approach |
| 16 | + |
| 17 | +- **Plan file**: [/nemo/lab/briscoej/home/users/kleshcv/.claude/plans/now-that-we-found-precious-kettle.md](/nemo/lab/briscoej/home/users/kleshcv/.claude/plans/now-that-we-found-precious-kettle.md) — approved by user 2026-05-13, then revised after the ATAC re-aggregation decision (this handoff supersedes the appendix A1 entry, which now becomes the critical path). |
| 18 | +- Template lineage: `embryo_rna_atac_spliced_unspliced_slurm.ipynb` (4-mod slurm/papermill, autogenerated 2026-04-19 from `embryo_rna_atac_spliced_unspliced.ipynb`, already Crick-pathed). |
| 19 | +- Settings reference: Phase 1B sweep [balanced_encoder_decoder_slurm_jobs.tsv](docs/notebooks/model_comparisons/balanced_encoder_decoder_slurm_jobs.tsv), 58-column schema, described in [phase-1-new-init-golden-wind.md](/nemo/lab/briscoej/home/users/kleshcv/.claude/plans/phase-1-new-init-golden-wind.md). |
| 20 | + |
| 21 | +--- |
| 22 | + |
| 23 | +## Current progress (built and verified) |
| 24 | + |
| 25 | +### Files created on 2026-05-13 |
| 26 | + |
| 27 | +| File | Purpose | Status | |
| 28 | +|---|---|---| |
| 29 | +| [cell2state_embryo/notebooks/benchmark/regularizedvi/mouse_gastrulation_rna_atac_spliced_unspliced_slurm.ipynb](/nemo/lab/briscoej/home/users/kleshcv/cell2state_embryo/notebooks/benchmark/regularizedvi/mouse_gastrulation_rna_atac_spliced_unspliced_slurm.ipynb) | 34-cell 4-mod training notebook | syntax-clean, all 17 imports resolve, **but data-loading cell still points at the OLD `anndata_atac.h5ad` (6 samples) — needs swap to the rebuilt h5ad + coordinate-overlap var intersection** | |
| 30 | +| [regularizedvi/docs/notebooks/mouse_gastrulation/known_marker_genes_briscoe_dv_mouse.csv](docs/notebooks/mouse_gastrulation/known_marker_genes_briscoe_dv_mouse.csv) | 147 rows, 27 categories (14 radial-glia, 13 neuron). Mouse-symbol-cased Briscoe DV progenitor markers (Sox2, Nkx2-2, …) | ready, no changes needed | |
| 31 | +| [regularizedvi/docs/notebooks/model_comparisons/mouse_gastrulation_slurm_jobs.tsv](docs/notebooks/model_comparisons/mouse_gastrulation_slurm_jobs.tsv) | 3 sweep rows; 58 cols matching Phase 1B schema; queue=gpu-normal, mem=100GB, time=2 days | ready (will need re-validation after the ATAC rebuild because mem may need bumping) | |
| 32 | + |
| 33 | +### Notebook edits applied (via `/tmp/edit_mouse_gastrulation_nb.py`) |
| 34 | +- **Edit 1**: Crick-paths header + title → mouse gastrulation |
| 35 | +- **Edit 2**: papermill `parameters` cell — full param block with mouse gastrulation paths; `wandb_project=regularizedvi_mouse_gastrulation`; `stratify_validation_key="celltype+sample"`; `markers_csv` + `c2m_results_folder` added; CRE parquet params removed |
| 36 | +- **Edit 3**: data-loading cell replaced — reads 3 h5ads, intersects on `obs_names`, splits velocyto layers into spliced/unspliced AnnDatas, builds MuData. **Currently broken on the var intersection point** — see "Blocking issue" below. |
| 37 | +- **Edit 4**: SEACell join (per-sample CSVs → `obs['SEACell']`, `obs['celltype_SEACell']`) — plotting only |
| 38 | +- **Edit 5**: `setup_mudata` call — `ambient_covariate_keys=["sample"]`, `dispersion_key="sample"`, `library_size_key="sample"`; `nn_conditioning_covariate_keys=["all"]` and `feature_scaling_covariate_keys=["all"]` use the constant `obs['all']="all"` column for single-category soft-disable (signature-checked: this signature accepts `list[str]`) |
| 39 | +- **Edit 6**: marker overlay cell — reads `known_marker_genes_briscoe_dv_mouse.csv` and plots per-domain |
| 40 | +- **Edit 7**: per-sample UMAP loop (mirrors cell2module per-sample style) |
| 41 | +- **Edit 8–13**: sweep of remaining embryo-specific obs column references (`Embryo`, `10x_kit`, `sample_id`, `cell_type_lvl*`, `Experiment`, `Section` → `sample`, `stage`, `celltype`, `celltype_SEACell`, etc.) in Cells 8 (data summary), 21 (UMAP color_vars), 22 (standard UMAP), 23 (small annotation set), 29 (LISI), 31 (UMAP grid) |
| 42 | + |
| 43 | +### Verification passes |
| 44 | +- Marker CSV: 147 rows, 27 categories, 61 unique genes — correct |
| 45 | +- `setup_mudata` signature accepts `list[str]` for nn_conditioning/feature_scaling (`["all"]` is valid) |
| 46 | +- All 17 imports resolve in the regularizedvi env |
| 47 | +- Notebook syntax checks clean (`/syntax-check`) |
| 48 | +- TSV column count consistent (58 cols × 3 rows + header) |
| 49 | + |
| 50 | +--- |
| 51 | + |
| 52 | +## Blocking issue — the ATAC h5ad coverage gap |
| 53 | + |
| 54 | +**Root cause discovered during data-loading dry run**: `/nemo/lab/briscoej/home/users/kleshcv/large_data/gastrulation_multiome_anndata/anndata_atac.h5ad` has mtime 2021-04-21 and contains only **6 samples** (E7.5/E8.0/E8.5 × rep1/rep2). The 5 missing samples (`E7.75_rep1`, `E8.75_rep1`, `E8.75_rep2`, `E8.5_CRISPR_T_KO`, `E8.5_CRISPR_T_WT`) are **NOT QC-failed** — they have ATAC fragment files (1.4–3.3 GB each, mtime 2022-08-18) but were never aggregated into the h5ad because the h5ad pre-dates them by ~16 months. |
| 55 | + |
| 56 | +Result: a naive multimodal intersection currently yields **32,420 cells × 6 samples × 3 stages (E7.5, E8.0, E8.5)** — missing the later E8.75 timepoint the user cares about. |
| 57 | + |
| 58 | +**The fix**: rebuild ATAC for all 11 samples from fragments via the cell2state SnapATAC2 tile loader, then intersect var names with the existing 203k peaks by **genomic coordinate overlap** (peak `chr/start/end` ∩ tile `chr/start/end`) — not exact name match, because tile names are like `chr1:1000-2000` while peak names are like `chr1-1234-2345` (Argelaguet's custom format). |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## What worked |
| 63 | + |
| 64 | +- **Editing large notebooks via a Python helper script** rather than NotebookEdit. The notebook (67 KB JSON / ~26k tokens) is over the Read tool's 25k token limit, which blocks NotebookEdit (which requires a prior Read). Workaround: write a small `nbformat`-style helper at `/tmp/edit_mouse_gastrulation_nb.py` that loads JSON, edits cells by source-string match, and writes back. Uses `bash scripts/helper_scripts/run_python_cmd.sh` to invoke with the correct env. Successful pattern for all 13 edits applied. |
| 65 | +- **Copying the 4-mod slurm template as base** (rather than the 2-mod `embryo_rna_atac.ipynb` or the model_comparisons bone marrow tutorial). The slurm template is already Crick-pathed and is the exact notebook the Phase 1B TSV invokes — minimal structural drift. |
| 66 | +- **Constant "all" obs column for soft-disabled covariate keys** — passes signature validation, avoids per-dataset code-path branches, keeps the API call structurally identical to the embryo template. |
| 67 | +- **Building the TSV via a script that copies reference Phase 1B rows + applies overrides** — guarantees column-count consistency. |
| 68 | +- **Title-casing gene symbols hyphen-segment-wise**: `lambda g: "-".join(seg[:1].upper() + seg[1:].lower() for seg in g.split("-"))` handles both `SOX2 → Sox2` and `NKX2-2 → Nkx2-2`. |
| 69 | +- **All Phase 1B settings already wired** in the embryo template — `use_modality_balanced_encoder_init`, `z_loc_init_scale`, `decoder_init_variance_target_fraction`, `decoder_burst_size_init_variance_target_fraction`, papermill type-conversion plumbing — no model-side code changes needed. |
| 70 | + |
| 71 | +## What didn't work / pitfalls to avoid |
| 72 | + |
| 73 | +- **Assuming the 5 missing ATAC samples failed QC**. They did NOT — they were simply never aggregated into the 2021 h5ad. Always verify against `original_with_atac/{sample}/atac_fragments.tsv.gz` existence and mtimes before claiming "QC fail". |
| 74 | +- **Read tool on full notebook**: fails on notebooks larger than ~25k tokens (~67 KB JSON). Use `inspect-notebook` skill for cell-level reads and the JSON-editing helper script pattern for writes. |
| 75 | +- **Wholesale notebook re-creation**: not needed. The 4-mod embryo template's model-side cells (training, attribution, LISI, parameter inspection) all reuse cleanly — only data-loading and plotting columns need swap. |
| 76 | +- **Exact-name var intersection between ATAC h5ads**: WILL FAIL. The existing `anndata_atac.h5ad` peaks use Argelaguet's custom naming (`chr-start-end` hyphenated) while SnapATAC2 tiles use `chr:start-end`. Always intersect by coordinates (`chr` + `start` + `end` tuples from `var` columns), never by `var_names`. |
| 77 | +- **`embryo_rna_atac.ipynb` (2-mod) as base**: has Sanger `/nfs/team205` paths and no slurm metadata cell — more rewriting than starting from the 4-mod slurm sibling. |
| 78 | +- **Bone marrow tutorial (`bone_marrow_multimodal_tutorial_early_stopping.ipynb`) as base**: lacks the papermill `parameters` block needed for TSV-driven slurm submission. |
| 79 | + |
| 80 | +## What's open / unresolved |
| 81 | + |
| 82 | +- **Validation for the burst row in mouse gastrulation**: bursting uses `dispersion_init=variance_burst_size`, which requires `dispersion_init_bio_frac` to be set (per Phase 1B plan). The current TSV row inherits `-` for `dispersion_init_bio_frac` from the embryo 4-mod row. Verify this is OK for a 2-modality MuData-like (RNA+ATAC+spliced+unspliced); embryo had `bio_frac='{"rna":0.99,"spliced":0.99,"unspliced":0.99,"atac":0.9}'` set in the notebook params cell, not the TSV. |
| 83 | +- **GPU memory**: TSV requests 100 GB, but this is a guess. Embryo 4-mod (424k cells) hit 99% of 210 GB. Mouse gastrulation ~50–80k paired cells (after the ATAC rebuild) should be smaller — but 4 modalities × wider feature space (~28k RNA + 32k spliced + 32k unspliced + ~200k ATAC peaks) may still push it. Monitor first run; bump to 150 GB if needed. |
| 84 | +- **SEACell coverage**: 6/11 SEACell.csv files were verified to exist; the other 5 samples (E7.75, E8.75 × 2, CRISPR × 2) — check whether matching SEACell.csv files exist before relying on them in the join. They should, since cell2module ran on all 11 RNA samples, but verify. |
| 85 | + |
| 86 | +--- |
| 87 | + |
| 88 | +## Next steps for fresh agent (in plan mode) |
| 89 | + |
| 90 | +### Step 1 — Rebuild ATAC h5ad for all 11 samples |
| 91 | + |
| 92 | +**Template**: [docs/notebooks/immune_integration/bm_pbmc_atac_loading.ipynb](docs/notebooks/immune_integration/bm_pbmc_atac_loading.ipynb) (env: `cell2state_v2026_cuda124_torch25`). |
| 93 | + |
| 94 | +**New notebook** (suggested path): `docs/notebooks/mouse_gastrulation/mouse_gastrulation_atac_loading.ipynb`. |
| 95 | + |
| 96 | +Steps inside the new notebook: |
| 97 | +1. Read the **RNA h5ad** (`/nemo/.../latest/data/processed/rna/anndata.h5ad`, 65,420 cells × 11 samples) — this drives which cells / barcodes will be counted. |
| 98 | +2. Add `fragment_file_path` column mapping `obs['sample']` → `/nemo/.../latest/data/original_with_atac/{sample}/atac_fragments.tsv.gz`. Verify all 11 paths exist (sizes 1.4–3.3 GB, mtime 2022-08-18; see this handoff's "Blocking issue" section for the table). |
| 99 | +3. Call `cell2state.utils.aggregation_v2.concatenate_h5ad(adata, variable_type="atac_tiles", batch_key="sample", loading_kwargs={path_to_reference=".../refdata-cellranger-arc-mm10-2020-A-2.0.0", path_to_fragment_file_key="fragment_file_path", max_frag_size_split=120, bin_size=1000, counting_strategy="paired-insertion", use_complete_path=True})` — exactly mirrors `bm_pbmc_atac_loading.ipynb` Cell 10. Output: ~65k cells × ~2.7M genome-wide 1kb tiles. |
| 100 | +4. Compute ATAC QC (`total_fragments`, `n_tiles_accessible`) per cell. Apply the QC threshold the user specifies (or use the embryo / immune defaults — confirm with user). |
| 101 | +5. Save to `/nemo/.../large_data/gastrulation_multiome_anndata/anndata_atac_tiles_1000bp_split120_11samples.h5ad`. |
| 102 | + |
| 103 | +**Submission**: this is a one-shot slurm job, not a TSV sweep. May need `cell2state_v2026_cuda124_torch25` env (not `regularizedvi`) — check `bm_pbmc_atac_loading.ipynb` Cell 0 for the env declaration. Memory budget: ~150–200 GB depending on chunking strategy. Genome reference `refdata-cellranger-arc-mm10-2020-A-2.0.0` must be on Crick — verify `/nemo/.../refdata-cellranger-arc-mm10-2020-A-2.0.0/genes/genes.gtf.gz` and `star/chrNameLength.txt` exist. |
| 104 | + |
| 105 | +### Step 2 — Coordinate-based var intersection helper |
| 106 | + |
| 107 | +User's exact phrasing: *"intersect them with vars from the already created object - exact names won't match, but we are looking for coordinate overlaps."* |
| 108 | + |
| 109 | +Need: a function that takes (a) the new tile h5ad (~2.7M genome-wide 1kb tiles, `var.index = "chr:start-end"`) and (b) the existing peak h5ad (~203k Argelaguet peaks, `var.index = "chr-start-end"`, columns `chr/start/end`), and returns a tile-subset whose genomic interval overlaps any peak. |
| 110 | + |
| 111 | +**Implementation approaches** (pick one in the plan): |
| 112 | +- **pyranges / bedtools-style** join via `pyranges` (already in regularizedvi env? check) or `pybedtools`. Convert both to BED-style intervals, do interval-join, take the set of tile IDs that hit ≥1 peak. |
| 113 | +- **Native pandas** with sorted `(chr, start)` and `np.searchsorted` for overlap detection — slower but no dependency. |
| 114 | +- **bedtools intersect** via subprocess if pyranges/pybedtools not available. |
| 115 | + |
| 116 | +Decide based on what's in the regularizedvi conda env — check `pyranges` import first. |
| 117 | + |
| 118 | +**Output**: a filtered ATAC tile h5ad (~200k–500k tiles, the union of all tiles overlapping any of the 203k peaks). This becomes the ATAC modality fed to RegularizedMultimodalVI. |
| 119 | + |
| 120 | +### Step 3 — Update the training notebook's data-loading cell |
| 121 | + |
| 122 | +Edit Cell 6 of [mouse_gastrulation_rna_atac_spliced_unspliced_slurm.ipynb](/nemo/lab/briscoej/home/users/kleshcv/cell2state_embryo/notebooks/benchmark/regularizedvi/mouse_gastrulation_rna_atac_spliced_unspliced_slurm.ipynb): |
| 123 | +- Replace the `atac_h5ad` param target with the **new tile h5ad** path (from Step 1). |
| 124 | +- Add the **coordinate-overlap var intersection** call (helper from Step 2) immediately after reading the new ATAC h5ad — load the existing `anndata_atac.h5ad` only to extract its `var[['chr','start','end']]` for the overlap set, then drop the existing h5ad. |
| 125 | +- Update the intersection-on-`obs_names` step: should yield ~55–75k cells × 11 samples × 5 stages (E7.5, E7.75, E8.0, E8.5, E8.75) plus the 2 CRISPR samples — verify this count in a dry run. |
| 126 | + |
| 127 | +Same JSON-editing helper script pattern as before: write `/tmp/edit_mouse_gastr_nb_v2.py` with one `stage` that only touches Cell 6 of the data loader. |
| 128 | + |
| 129 | +### Step 4 — Re-verify and submit |
| 130 | + |
| 131 | +- `/check-signature` on any new helper functions used. |
| 132 | +- `/syntax-check` on the updated notebook. |
| 133 | +- `/check-imports` for any new imports (`pyranges` etc.). |
| 134 | +- Data-loading dry run: confirm cell count (expect 55–75k), confirm 11 samples / 5 stages. |
| 135 | +- `/verify-implementation` — mandatory pre-submission gate per CLAUDE.md. |
| 136 | +- Submit via `bash scripts/helper_scripts/submit_papermill_slurm.sh docs/notebooks/model_comparisons/mouse_gastrulation_slurm_jobs.tsv`. |
| 137 | + |
| 138 | +--- |
| 139 | + |
| 140 | +## Key paths quick-reference |
| 141 | + |
| 142 | +``` |
| 143 | +# Plan (read this first) |
| 144 | +/nemo/lab/briscoej/home/users/kleshcv/.claude/plans/now-that-we-found-precious-kettle.md |
| 145 | +
|
| 146 | +# Built files (ready) |
| 147 | +/nemo/lab/briscoej/home/users/kleshcv/cell2state_embryo/notebooks/benchmark/regularizedvi/mouse_gastrulation_rna_atac_spliced_unspliced_slurm.ipynb |
| 148 | +/nemo/lab/briscoej/home/users/kleshcv/my_packages/regularizedvi/docs/notebooks/mouse_gastrulation/known_marker_genes_briscoe_dv_mouse.csv |
| 149 | +/nemo/lab/briscoej/home/users/kleshcv/my_packages/regularizedvi/docs/notebooks/model_comparisons/mouse_gastrulation_slurm_jobs.tsv |
| 150 | +
|
| 151 | +# Templates to copy |
| 152 | +/nemo/lab/briscoej/home/users/kleshcv/cell2state_embryo/notebooks/benchmark/regularizedvi/embryo_rna_atac_spliced_unspliced_slurm.ipynb # 4-mod training (already copied) |
| 153 | +/nemo/lab/briscoej/home/users/kleshcv/my_packages/regularizedvi/docs/notebooks/immune_integration/bm_pbmc_atac_loading.ipynb # ATAC tile loader (next step) |
| 154 | +
|
| 155 | +# Data inputs |
| 156 | +/nemo/lab/briscoej/home/users/kleshcv/large_data/gastrulation_multiome_anndata/latest/data/processed/rna/anndata.h5ad # RNA total (65k × 32k, 11 samples) |
| 157 | +/nemo/lab/briscoej/home/users/kleshcv/large_data/gastrulation_multiome_anndata/latest/data/processed/rna/velocyto/anndata_velocyto.h5ad # spliced+unspliced (65k × 32k, 11 samples) |
| 158 | +/nemo/lab/briscoej/home/users/kleshcv/large_data/gastrulation_multiome_anndata/anndata_atac.h5ad # OLD ATAC peaks (38k × 203k, 6 samples) — keep ONLY for peak var coordinates |
| 159 | +/nemo/lab/briscoej/home/users/kleshcv/large_data/gastrulation_multiome_anndata/latest/data/original_with_atac/{sample}/atac_fragments.tsv.gz # ATAC fragments for ALL 11 samples |
| 160 | +
|
| 161 | +# SEACell partitions (for plotting only, joined post-training) |
| 162 | +/nemo/lab/briscoej/home/users/kleshcv/my_packages/cell2module/docs/notebooks/results/mouse_gastrulation/per_sample_analysis_{sample}__cell2module/SEACell.csv |
| 163 | +
|
| 164 | +# Briscoe DV marker source notebook |
| 165 | +/nemo/lab/briscoej/home/users/kleshcv/cell2state_embryo/notebooks/benchmark/section_suspension_embryo_10x_kit/affinity_analysis_from_annotation_v2.ipynb # Cell 151 = dv_progenitor_genes dict; Cell 152 = dv_domain_label_v2 derivation |
| 166 | +``` |
| 167 | + |
| 168 | +## Project conventions to follow |
| 169 | + |
| 170 | +- All Python via `bash scripts/helper_scripts/run_python_cmd.sh` (NOT bare `python3` or `conda run`). |
| 171 | +- Default float dtype: `float32`. Integer dtypes are nuanced — ask before assuming. |
| 172 | +- Helper scripts go in `scripts/claude_helper_scripts/`. One-off scripts in `/tmp/` are fine but should also follow the `run_python_cmd.sh` convention. |
| 173 | +- `gh` CLI invocation on Crick: `~/.conda/envs/cell2state_v2026_cuda124_torch25/bin/gh <command>`. |
| 174 | +- GPU specs (per CLAUDE.md): bsub on Sanger, sbatch on Crick. Mouse gastrulation 4-mod target queue = `gpu-normal`, partition `ga100` (non-burst) / `gh100` (burst). |
| 175 | +- Always invoke `/verify-implementation` before any irreversible action (submission, push). |
| 176 | +- Notebook editing: use `inspect-notebook` skill to read cells; use the JSON-editing helper script pattern to write — the harness Read tool fails on large notebooks (>25k tokens). |
0 commit comments