use std::error::Error;
use std::path::Path;
use bio::stats::{bayesian, LogProb};
use itertools::Itertools;
use rust_htslib::bcf;
use rust_htslib::bcf::Read;
use model;
use utils;
use Event;
pub fn control_fdr<E: Event, R, W>(
inbcf: R,
outbcf: Option<W>,
events: &[E],
vartype: &model::VariantType,
alpha: LogProb,
) -> Result<(), Box<Error>>
where
R: AsRef<Path>,
W: AsRef<Path>,
{
let mut inbcf_reader = bcf::Reader::from_path(&inbcf)?;
let header = bcf::Header::from_template(inbcf_reader.header());
let mut outbcf = match outbcf {
Some(p) => bcf::Writer::from_path(p, &header, false, false)?,
None => bcf::Writer::from_stdout(&header, false, false)?,
};
let mut threshold = None;
if alpha != LogProb::ln_one() {
let prob_dist = utils::collect_prob_dist(&mut inbcf_reader, events, vartype)?;
let pep_dist = prob_dist
.into_iter()
.rev()
.map(|p| LogProb(*p).ln_one_minus_exp())
.collect_vec();
let fdrs = bayesian::expected_fdr(&pep_dist);
if fdrs[0] > alpha {
threshold = Some(LogProb::ln_one());
} else {
for i in (0..fdrs.len()).rev() {
if fdrs[i] <= alpha && (i == 0 || pep_dist[i] != pep_dist[i - 1]) {
let pep = pep_dist[i];
threshold = Some(pep.ln_one_minus_exp());
break;
}
}
}
}
let mut inbcf_reader = bcf::Reader::from_path(&inbcf)?;
utils::filter_by_threshold(&mut inbcf_reader, threshold, &mut outbcf, events, vartype)?;
Ok(())
}