Skip to content

Add mean_zero_coverage_length coverage method#292

Open
wwood wants to merge 1 commit into
mainfrom
claude/avg-zero-coverage-length-urc193
Open

Add mean_zero_coverage_length coverage method#292
wwood wants to merge 1 commit into
mainfrom
claude/avg-zero-coverage-length-urc193

Conversation

@wwood

@wwood wwood commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a new coverage method, mean_zero_coverage_length, that reports the average length (in base pairs) of the regions of each contig or genome that have zero coverage.

This builds on top of #290 (the coverm makedb branch), so its diff is included here; this PR's own changes are the new coverage method.

Behaviour

  • Within a covered contig, each maximal run of consecutive zero-coverage bases is one region; the method reports the average region length.
  • A sequence with no reads mapped at all is treated as a single zero-coverage region spanning its whole length (e.g. an absent 1000 bp contig → 1000).
  • A sequence with no zero-coverage positions (fully covered) is reported as 0.

Cross-path consistency

Genome coverage is computed via two code paths — streaming (--separator) and non-streaming (--genome-fasta-files). For an entirely-unobserved multi-contig genome, the streaming path only knows the genome's total length (via print_zero_coverage). To keep results identical regardless of input format, an entry with zero mapped reads is defined as a single region of its full length. The estimator's num_mapped_reads is available in both calculate_coverage and print_zero_coverage, so both paths agree, and it also distinguishes an absent entry (→ length) from a fully-covered one (→ 0).

Like the other structural estimators (length, count, reads_per_base, anir), this method does not compute a covered fraction and so cannot be combined with --min-covered-fraction > 0 (it errors with a clear message).

Changes

  • src/mosdepth_genome_coverage_estimators.rs: new MeanZeroCoverageLengthEstimator variant, all trait arms, and 4 unit tests.
  • src/bin/coverm.rs: method dispatch and --min-covered-fraction incompatibility guard.
  • src/cli.rs: added to both genome/contig value-parser lists and both help tables.
  • src/contig.rs: end-to-end test (covered seq1 → 68.25, uncovered seq2 → 1000).
  • tests/test_cmdline.rs: cmdline integration test.
  • README.md: row in the calculation-methods table.

Testing

  • New unit, contig, and cmdline tests pass.
  • cargo clippy -- -D warnings and cargo fmt -- --check are clean (enforced by the pre-commit hook).
  • One unrelated, pre-existing test (test_streaming_bam_file) fails in this environment only because samtools/bwa are not installed.

The generated docs/coverm-*.html man pages were not regenerated, as that requires the man/pandoc tooling used at release time; the source README and CLI help text are updated.

https://claude.ai/code/session_0126FFDNupzAHRS5m74JA9Zp


Generated by Claude Code

Add a new coverage method, mean_zero_coverage_length, that reports the
average length (in base pairs) of the regions of each contig or genome
that have zero coverage.

Within a covered contig, each maximal run of consecutive zero-coverage
bases is one region. An entirely-unobserved contig (or, in genome mode,
an entry with no reads mapped at all) is treated as a single
zero-coverage region spanning its whole length, which keeps results
identical regardless of whether the streaming (print_zero_coverage) or
non-streaming (calculate_coverage) code path is taken. A contig/genome
with no zero-coverage positions is reported as 0.

Like the other structural estimators (length, count, reads_per_base,
anir), this method does not compute a covered fraction and so cannot be
combined with --min-covered-fraction > 0.

Includes unit tests for the estimator logic, an end-to-end contig test,
a cmdline integration test, and README/help documentation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dbff109387

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +892 to +898
if *num_mapped_reads == 0 {
// No reads mapped to this entry at all, so the whole entry is
// a single zero-coverage region spanning its full length.
// Reporting the total length here (rather than the per-contig
// average) keeps results identical to the print_zero_coverage
// path, which only knows the entry's total length.
return unobserved_bases as f32;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid bypassing --no-zeros for unmapped genomes

In genome mode with --no-zeros, src/genome.rs decides whether to print an entry by checking whether any calculated coverage is > 0; returning the entry length here when num_mapped_reads == 0 makes completely unmapped genomes look nonzero for -m mean_zero_coverage_length, so coverm genome --no-zeros -m mean_zero_coverage_length will still emit genomes with zero read coverage. This needs a separate path for reporting the length without using that positive value as the print/no-print signal.

Useful? React with 👍 / 👎.

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.

2 participants