use std::f64;
use std::str;
use rgsl::randist::poisson::poisson_pdf;
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;
use bio::stats::LogProb;
use rust_htslib::bam;
use rust_htslib::bam::record::CigarString;
#[derive(Clone, Debug)]
pub struct Observation {
pub prob_mapping: LogProb,
pub prob_mismapping: LogProb,
pub prob_alt: LogProb,
pub prob_ref: LogProb,
pub prob_sample_alt: LogProb,
pub evidence: Evidence,
}
impl Observation {
pub fn new(
prob_mapping: LogProb,
prob_mismapping: LogProb,
prob_alt: LogProb,
prob_ref: LogProb,
prob_sample_alt: LogProb,
evidence: Evidence,
) -> Self {
Observation {
prob_mapping: prob_mapping,
prob_mismapping: prob_mismapping,
prob_alt: prob_alt,
prob_ref: prob_ref,
prob_sample_alt: prob_sample_alt,
evidence: evidence,
}
}
pub fn is_alignment_evidence(&self) -> bool {
if let Evidence::Alignment(_) = self.evidence {
true
} else {
false
}
}
}
pub fn poisson_pmf(count: u32, mu: f64) -> LogProb {
if mu == 0.0 {
if count == 0 {
LogProb::ln_one()
} else {
LogProb::ln_zero()
}
} else {
LogProb(poisson_pdf(count, mu).ln())
}
}
impl Serialize for Observation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("Observation", 3)?;
s.serialize_field("prob_mapping", &self.prob_mapping)?;
s.serialize_field("prob_mismapping", &self.prob_mismapping)?;
s.serialize_field("prob_alt", &self.prob_alt)?;
s.serialize_field("prob_ref", &self.prob_ref)?;
s.serialize_field("prob_sample_alt", &self.prob_sample_alt)?;
s.serialize_field("evidence", &self.evidence)?;
s.end()
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Evidence {
InsertSize(String),
Alignment(String),
}
impl Evidence {
pub fn dummy_alignment() -> Self {
Evidence::Alignment("Dummy-Alignment".to_owned())
}
pub fn dummy_insert_size(insert_size: u32) -> Self {
Evidence::InsertSize(format!("insert-size={}", insert_size))
}
pub fn insert_size(
insert_size: u32,
left: &CigarString,
right: &CigarString,
left_record: &bam::Record,
right_record: &bam::Record,
p_left_ref: LogProb,
p_left_alt: LogProb,
p_right_ref: LogProb,
p_right_alt: LogProb,
p_isize_ref: LogProb,
p_isize_alt: LogProb,
) -> Self {
Evidence::InsertSize(format!(
"left: cigar={} ({:e} vs {:e}), right: cigar={} ({:e} vs {:e}), insert-size={} ({:e} vs {:e}), qname={}, left: AS={:?}, XS={:?}, right: AS={:?}, XS={:?}",
left, p_left_ref.exp(), p_left_alt.exp(),
right, p_right_ref.exp(), p_right_alt.exp(),
insert_size, p_isize_ref.exp(), p_isize_alt.exp(),
str::from_utf8(left_record.qname()).unwrap(),
left_record.aux(b"AS").map(|a| a.integer()),
left_record.aux(b"XS").map(|a| a.integer()),
right_record.aux(b"AS").map(|a| a.integer()),
right_record.aux(b"XS").map(|a| a.integer())
))
}
pub fn alignment(cigar: &CigarString, record: &bam::Record) -> Self {
Evidence::Alignment(format!(
"cigar={}, qname={}, AS={:?}, XS={:?}",
cigar,
str::from_utf8(record.qname()).unwrap(),
record.aux(b"AS").map(|a| a.integer()),
record.aux(b"XS").map(|a| a.integer())
))
}
}