///|
pub(all) struct WindowSummary {
chrom : String
interval : GenomicInterval?
record_count : Int
snv_count : Int
indel_count : Int
filtered_count : Int
mean_qual : Double?
} derive(Debug, Eq)
///|
pub fn summarize_window(
document : VcfDocument,
chrom : String,
interval : GenomicInterval?,
) -> WindowSummary {
let selected = pipeline_query(
document,
chrom,
match interval {
Some(value) => value.start
None => 1
},
match interval {
Some(value) => value.end
None => 2147483647
},
)
let mut snv_count = 0
let mut indel_count = 0
let mut filtered_count = 0
let mut quality_sum = 0.0
let mut quality_count = 0
for record in selected {
if record_is_snv(record) {
snv_count = snv_count + 1
}
if record_is_indel(record) {
indel_count = indel_count + 1
}
if record.filters.length() > 0 && !record.filters.contains("PASS") {
filtered_count = filtered_count + 1
}
match record.qual {
Some(value) => {
quality_sum = quality_sum + value
quality_count = quality_count + 1
}
None => ()
}
}
{
chrom,
interval,
record_count: selected.length(),
snv_count,
indel_count,
filtered_count,
mean_qual: if quality_count == 0 {
None
} else {
Some(quality_sum / quality_count.to_double())
},
}
}
///|
pub fn summarize_fixed_windows(
document : VcfDocument,
chrom : String,
start : Int,
end : Int,
width : Int,
) -> Array[WindowSummary] {
let windows : Array[WindowSummary] = []
if width <= 0 || start > end {
return windows
}
let mut cursor = start
while cursor <= end {
let window_end = min_window(end, cursor + width - 1)
windows.push(
summarize_window(document, chrom, make_interval(cursor, window_end)),
)
cursor = window_end + 1
}
windows
}
///|
pub fn window_density(summary : WindowSummary) -> Double {
match summary.interval {
Some(value) if value.end >= value.start =>
summary.record_count.to_double() / interval_width(Some(value)).to_double()
_ => 0.0
}
}
///|
pub fn window_snv_fraction(summary : WindowSummary) -> Double? {
if summary.record_count == 0 {
None
} else {
Some(summary.snv_count.to_double() / summary.record_count.to_double())
}
}
///|
pub fn window_filter_fraction(summary : WindowSummary) -> Double? {
if summary.record_count == 0 {
None
} else {
Some(summary.filtered_count.to_double() / summary.record_count.to_double())
}
}
///|
pub fn window_is_empty(summary : WindowSummary) -> Bool {
summary.record_count == 0
}
///|
pub fn window_merge_summaries(
summaries : Array[WindowSummary],
) -> WindowSummary {
if summaries.length() == 0 {
return {
chrom: "",
interval: None,
record_count: 0,
snv_count: 0,
indel_count: 0,
filtered_count: 0,
mean_qual: None,
}
}
let first = summaries[0]
let mut record_count = 0
let mut snv_count = 0
let mut indel_count = 0
let mut filtered_count = 0
let mut quality_sum = 0.0
let mut quality_count = 0
for summary in summaries {
record_count = record_count + summary.record_count
snv_count = snv_count + summary.snv_count
indel_count = indel_count + summary.indel_count
filtered_count = filtered_count + summary.filtered_count
match summary.mean_qual {
Some(value) => {
quality_sum = quality_sum + value
quality_count = quality_count + 1
}
None => ()
}
}
{
chrom: first.chrom,
interval: first.interval,
record_count,
snv_count,
indel_count,
filtered_count,
mean_qual: if quality_count == 0 {
None
} else {
Some(quality_sum / quality_count.to_double())
},
}
}
///|
pub fn format_window_summary(summary : WindowSummary) -> String {
"\{summary.chrom}\t\{format_interval(summary.interval)}\t\{summary.record_count}\t\{summary.snv_count}\t\{summary.indel_count}\t\{summary.filtered_count}\n"
}
///|
fn min_window(left : Int, right : Int) -> Int {
if left < right {
left
} else {
right
}
}