Add fuzzy species SNP scanning for long reads - #1
jiehua1995 wants to merge 14 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Species-mode SNP quality handling currently double-subtracts Phred+33 (breaking filtering) and the new unit tests include a non-existent SpeciesArgs.revcomp field, causing compilation/test failures.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a new motifscan species subcommand that performs fuzzy long-read locus matching using shared k-mer anchors plus semi-global alignment, then assigns mel/sim via automatically extracted diagnostic substitution SNPs (with per-sample summary + SNP QC outputs). This extends MotifScan beyond exact motif counting while keeping existing motifscan count behavior unchanged.
Changes:
- Introduces
src/species.rsimplementing anchor indexing, candidate evaluation via semi-global edit alignment, SNP extraction from paired references, and CSV reporting (plus unit tests). - Adds CLI wiring + help text for the new
speciesmode (src/cli.rs,src/lib.rs) and new documentation/examples (doc/species-mode.md,doc/dmel_dsim_pairs.csv). - Updates CI to run
cargo testin addition to fmt/clippy (.github/workflows/ci.yml).
File summaries
| File | Description |
|---|---|
| src/species.rs | Implements the new long-read fuzzy locus scan + SNP voting logic, outputs, and tests. |
| src/lib.rs | Exposes the species module and routes the motifscan species subcommand. |
| src/cli.rs | Defines SpeciesArgs and registers the species subcommand/validation. |
| doc/species-mode.md | Documents algorithm, inputs, outputs, and QC interpretation for species mode. |
| doc/dmel_dsim_pairs.csv | Provides an example mel/sim pair CSV for users. |
| .github/workflows/ci.yml | Adds cargo test to CI checks and tweaks a Windows output path. |
Review details
- Files reviewed: 6/6 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| threads: 1, | ||
| progress: false, | ||
| revcomp: true, | ||
| anchor_k: 5, | ||
| anchors_per_locus: 4, |
| let reference = match strand { | ||
| ScanStrand::Forward => locus.mel_seq.clone(), | ||
| ScanStrand::Reverse => revcomp(&locus.mel_seq), | ||
| }; | ||
| let slack = args.alignment_slack as isize; | ||
| let from = (estimated_start - slack).max(0) as usize; | ||
| let to = (estimated_start + reference.len() as isize + slack) | ||
| .max(0) | ||
| .min(read.len() as isize) as usize; | ||
| if to <= from { | ||
| return None; | ||
| } | ||
| let target = &read[from..to]; | ||
| let alignment = semi_global_align(&reference, target); |
Adds a new
motifscan speciesmode for long-read DNA/cDNA data.Key changes:
sample<TAB>pathinput listsThe existing exact
motifscan countbehavior is left unchanged.