use noodles::bam::io::reader::Query;
use noodles::sam::alignment::Record;
use os_pipe::PipeWriter;
use std::fs::{OpenOptions, create_dir_all};
use std::io;
use std::io::{BufWriter, Write};
use noodles::sam::alignment::record::Flags;
use std::sync::{Arc, Mutex};
#[derive(Debug)]
pub enum BAMRecordError {
IoError(std::io::Error),
NoFirstRecord,
IncorrectSel,
}
impl From<std::io::Error> for BAMRecordError {
fn from(err: std::io::Error) -> Self {
BAMRecordError::IoError(err)
}
}
pub fn start_end_counts(
starts_vector: &[(i32, i32)],
chrom_size: i32,
smoothsize: i32,
stepsize: i32,
) -> (Vec<u32>, Vec<i32>) {
let mut v_coordinate_positions: Vec<i32> = Vec::new(); let mut v_coord_counts: Vec<u32> = Vec::new();
let mut coordinate_position = 1;
let mut count: i32 = 0;
let mut coordinate_value: (i32, i32);
let mut prev_coordinate_value = 0;
let mut adjusted_start_site: (i32, i32);
let mut current_end_site: (i32, i32);
let mut collected_end_sites: Vec<(i32, i32)> = Vec::new();
let mut collected_counts: Vec<i32> = Vec::new();
adjusted_start_site = starts_vector[0]; let original_position = adjusted_start_site.0;
adjusted_start_site.0 = (original_position - smoothsize).max(1);
let current_score = adjusted_start_site.1;
collected_counts.insert(0, current_score);
count += current_score;
current_end_site = adjusted_start_site;
current_end_site.0 = original_position + smoothsize + 1;
while coordinate_position < adjusted_start_site.0 {
coordinate_position += stepsize;
}
for coord in starts_vector.iter().skip(1) {
coordinate_value = *coord;
let original_position = coordinate_value.0; adjusted_start_site = coordinate_value;
adjusted_start_site.0 = (original_position - smoothsize).max(1);
let mut new_end_site = adjusted_start_site;
new_end_site.0 = original_position + smoothsize + 1;
collected_end_sites.push(new_end_site);
if adjusted_start_site.0 == prev_coordinate_value {
let current_score = adjusted_start_site.1;
collected_counts.insert(0, current_score); count += current_score;
continue;
}
while coordinate_position < adjusted_start_site.0 {
while current_end_site.0 == coordinate_position {
let most_recent_score = collected_counts.remove(0);
count -= most_recent_score; if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site.0 = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
v_coord_counts.push(count as u32);
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
let current_score = adjusted_start_site.1;
collected_counts.insert(0, current_score); count += current_score;
prev_coordinate_value = adjusted_start_site.0;
}
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site.0 == coordinate_position {
let most_recent_score = collected_counts.remove(0);
count -= most_recent_score; if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site.0 = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
v_coord_counts.push(count as u32);
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
(v_coord_counts, v_coordinate_positions)
}
#[allow(unused_variables)]
pub fn core_counts(
starts_vector: &[(i32, i32)],
ends_vector: &[(i32, i32)],
chrom_size: i32,
stepsize: i32,
) -> (Vec<u32>, Vec<i32>) {
let mut v_coordinate_positions: Vec<i32> = Vec::new(); let mut v_coord_counts: Vec<u32> = Vec::new();
let mut coordinate_position = 1;
let mut count = 0;
let mut coordinate_value: (i32, i32);
let mut prev_coordinate_value = 0;
let mut current_start_site: (i32, i32);
let mut current_end_site: (i32, i32);
let mut collected_end_sites: Vec<(i32, i32)> = Vec::new();
let mut collected_counts: Vec<i32> = Vec::new();
current_start_site = starts_vector[0]; current_end_site = ends_vector[0];
if current_start_site.0 < 1 {
current_start_site.0 = 1;
}
let current_score = current_start_site.1;
collected_counts.insert(0, current_score);
count += current_score;
while coordinate_position < current_start_site.0 {
coordinate_position += stepsize;
}
for (index, coord) in starts_vector.iter().enumerate() {
if index == 0 {
continue; }
coordinate_value = *coord;
current_start_site = coordinate_value;
if current_start_site.0 < 1 {
current_start_site.0 = 1;
}
let current_index = index;
collected_end_sites.push(ends_vector[current_index]);
if current_start_site.0 == prev_coordinate_value {
let current_score = current_start_site.1;
collected_counts.insert(0, current_score); count += current_score;
continue;
}
while coordinate_position < current_start_site.0 {
while current_end_site.0 == coordinate_position {
let most_recent_score = collected_counts.remove(0);
count -= most_recent_score; if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site.0 = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
v_coord_counts.push(count as u32);
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
let current_score = current_start_site.1;
count += current_score;
collected_counts.insert(0, current_score);
prev_coordinate_value = current_start_site.0;
}
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site.0 == coordinate_position {
let most_recent_score = collected_counts.remove(0);
count -= most_recent_score;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site.0 = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
v_coord_counts.push(count as u32);
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
(v_coord_counts, v_coordinate_positions)
}
#[allow(clippy::too_many_arguments)]
pub fn fixed_start_end_counts_bam(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
smoothsize: i32,
stepsize: i32,
output_type: &str,
chromosome_name: &String,
bwfileheader: &str,
out_sel: &str,
std_out_sel: bool,
) -> (Vec<u32>, Vec<i32>) {
let mut v_coordinate_positions: Vec<i32> = Vec::new(); let v_coord_counts: Vec<u32> = Vec::new();
let mut coordinate_position = 1;
let mut count: i32 = 0;
let mut prev_coordinate_value = 0;
let mut current_end_site: i32;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record = records.next().unwrap().unwrap();
let mut adjusted_start_site: i32 = match out_sel {
"start" => first_record.alignment_start().unwrap().unwrap().get() as i32,
"end" => first_record.alignment_end().unwrap().unwrap().get() as i32,
_ => {
panic!("unknown output selection must be either 'start', 'end', 'core'")
}
};
let original_position = adjusted_start_site;
adjusted_start_site = (original_position - smoothsize).max(1);
let file = set_up_file_output(
output_type,
adjusted_start_site,
chromosome_name,
bwfileheader,
stepsize,
out_sel,
std_out_sel,
);
let file = file.unwrap();
let mut buf = BufWriter::new(file);
current_end_site = original_position + smoothsize + 1;
while coordinate_position < adjusted_start_site {
coordinate_position += stepsize;
}
for coord in records {
let coordinate_value: i32 = match out_sel {
"start" => coord.unwrap().alignment_start().unwrap().unwrap().get() as i32,
"end" => coord.unwrap().alignment_end().unwrap().unwrap().get() as i32,
_ => {
panic!("unknown output selection must be either 'start', 'end', 'core'")
}
};
let original_position = coordinate_value;
adjusted_start_site = (original_position - smoothsize).max(1);
let current_score = adjusted_start_site;
count += current_score;
let new_end_site = original_position + smoothsize + 1;
collected_end_sites.push(new_end_site);
if adjusted_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < adjusted_start_site {
while current_end_site == coordinate_position {
count -= current_score;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
match output_type {
"wig" => {
writeln!(&mut buf, "{}", count).unwrap();
}
"bedgraph" => {
writeln!(
&mut buf,
"{}\t{}\t{}\t{}",
chromosome_name, adjusted_start_site, current_end_site, count
)
.unwrap();
}
_ => {}
}
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
prev_coordinate_value = adjusted_start_site;
}
count += 1;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
let current_score = adjusted_start_site;
count -= current_score;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
match output_type {
"wig" => {
writeln!(&mut buf, "{}", count).unwrap();
}
"bedgraph" => {
writeln!(
&mut buf,
"{}\t{}\t{}\t{}",
chromosome_name, adjusted_start_site, current_end_site, count
)
.unwrap();
}
_ => {}
}
v_coordinate_positions.push(coordinate_position);
}
coordinate_position += 1;
}
buf.flush().unwrap();
(v_coord_counts, v_coordinate_positions)
}
pub fn fixed_core_counts_bam_to_bw(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
stepsize: i32,
chromosome_name: &String,
write_fd: Arc<Mutex<PipeWriter>>,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
let mut coordinate_position = 1;
let mut count: i32 = 0;
let mut prev_coordinate_value = 0;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record_option = records.next();
let first_record = match first_record_option {
Some(Ok(record)) => record, Some(Err(err)) => {
eprintln!(
"Error reading the first record for chrom: {} {:?} Skipping...",
chromosome_name, err
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord); }
None => {
eprintln!(
"Error reading the first record for chrom: {} Skipping...",
chromosome_name
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord);
}
};
let mut current_start_site = first_record.alignment_start().unwrap().unwrap().get() as i32;
let mut current_end_site = first_record.alignment_end().unwrap().unwrap().get() as i32;
if current_start_site < 1 {
current_start_site = 1;
}
while coordinate_position < current_start_site {
coordinate_position += stepsize;
}
for coord in records {
let unwrapped_coord = coord.unwrap().clone();
let mut current_start_site =
unwrapped_coord.alignment_start().unwrap().unwrap().get() as i32;
let new_end_site = unwrapped_coord.alignment_end().unwrap().unwrap().get() as i32;
count += 1;
if current_start_site < 1 {
current_start_site = 1;
}
collected_end_sites.push(new_end_site);
if current_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < current_start_site {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
coordinate_position,
coordinate_position + 1,
count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
}
coordinate_position += 1;
}
prev_coordinate_value = current_start_site;
}
count += 1;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
coordinate_position,
coordinate_position + 1,
count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
}
coordinate_position += 1;
}
Ok(())
}
pub fn fixed_start_end_counts_bam_to_bw(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
smoothsize: i32,
stepsize: i32,
chromosome_name: &String,
out_sel: &str,
write_fd: Arc<Mutex<PipeWriter>>,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
let mut coordinate_position = 1;
let mut count: i32 = 0;
let mut prev_coordinate_value = 0;
let mut current_end_site: i32;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record_option = records.next();
let first_record = match first_record_option {
Some(Ok(record)) => record, Some(Err(err)) => {
eprintln!(
"Error reading the first record for chrom: {} {:?} Skipping...",
chromosome_name, err
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord); }
None => {
eprintln!(
"Error reading the first record for chrom: {} Skipping...",
chromosome_name
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord);
}
};
let mut adjusted_start_site: i32 = match out_sel {
"start" => first_record.alignment_start().unwrap().unwrap().get() as i32,
"end" => first_record.alignment_end().unwrap().unwrap().get() as i32,
_ => {
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::IncorrectSel); }
};
let original_position = adjusted_start_site;
adjusted_start_site = (original_position - smoothsize).max(1);
current_end_site = (original_position + smoothsize + 1).min(chrom_size);
while coordinate_position < adjusted_start_site {
coordinate_position += stepsize;
}
for coord in records {
let coordinate_value: i32 = match out_sel {
"start" => coord.unwrap().alignment_start().unwrap().unwrap().get() as i32,
"end" => coord.unwrap().alignment_end().unwrap().unwrap().get() as i32,
_ => {
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
return Err(BAMRecordError::IncorrectSel);
}
};
let original_position = coordinate_value;
adjusted_start_site = (original_position - smoothsize).max(1);
count += 1;
let new_end_site = (original_position + smoothsize + 1).min(chrom_size);
collected_end_sites.push(new_end_site);
if adjusted_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < adjusted_start_site {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
coordinate_position,
coordinate_position + 1,
count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
}
coordinate_position += 1;
}
prev_coordinate_value = adjusted_start_site;
}
count += 1;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if coordinate_position % stepsize == 0 {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
coordinate_position,
coordinate_position + 1,
count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
}
coordinate_position += 1;
}
drop(writer);
Ok(())
}
pub fn variable_start_end_counts_bam_to_bw(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
smoothsize: i32,
stepsize: i32,
chromosome_name: &String,
out_sel: &str,
write_fd: Arc<Mutex<PipeWriter>>,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
let mut coordinate_position = 1;
let mut prev_count: i32 = 0;
let mut count: i32 = 0;
let mut prev_coordinate_value = 0;
let mut current_end_site: i32;
let mut bg_prev_coord: i32 = 0;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record_option = records.next();
let first_record = match first_record_option {
Some(Ok(record)) => record, Some(Err(err)) => {
eprintln!(
"Error reading the first record for {} chrom: {} {:?} Skipping...",
out_sel, chromosome_name, err
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord); }
None => {
eprintln!(
"No records for {} chrom: {} Skipping...",
out_sel, chromosome_name
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord);
}
};
let mut adjusted_start_site: i32 = match out_sel {
"start" => first_record.alignment_start().unwrap().unwrap().get() as i32,
"end" => first_record.alignment_end().unwrap().unwrap().get() as i32,
_ => {
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::IncorrectSel); }
};
let original_position = adjusted_start_site;
adjusted_start_site = (original_position - smoothsize).max(1);
current_end_site = (original_position + smoothsize + 1).min(chrom_size);
while coordinate_position < adjusted_start_site {
coordinate_position += stepsize;
}
for coord in records {
let coordinate_value: i32 = match out_sel {
"start" => coord.unwrap().alignment_start().unwrap().unwrap().get() as i32,
"end" => coord.unwrap().alignment_end().unwrap().unwrap().get() as i32,
_ => {
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
return Err(BAMRecordError::IncorrectSel);
}
};
let original_position = coordinate_value;
adjusted_start_site = (original_position - smoothsize).max(1);
count += 1;
let new_end_site = (original_position + smoothsize + 1).min(chrom_size);
collected_end_sites.push(new_end_site);
if adjusted_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < adjusted_start_site {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name, bg_prev_coord, coordinate_position, prev_count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
prev_coordinate_value = adjusted_start_site;
}
count += 1;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name, bg_prev_coord, coordinate_position, prev_count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
drop(writer);
Ok(())
}
pub fn variable_core_counts_bam_to_bw(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
stepsize: i32,
chromosome_name: &String,
write_fd: Arc<Mutex<PipeWriter>>,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
let mut coordinate_position = 1;
let mut prev_count: i32 = 0;
let mut count: i32 = 0;
let mut prev_coordinate_value = 0;
let mut bg_prev_coord: i32 = 0;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record_option = records.next();
let first_record = match first_record_option {
Some(Ok(record)) => record, Some(Err(err)) => {
eprintln!(
"Error reading the first record for core chrom: {} {:?} Skipping...",
chromosome_name, err
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord); }
None => {
eprintln!("No records for core chrom: {} Skipping...", chromosome_name);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord);
}
};
let mut current_start_site = first_record.alignment_start().unwrap().unwrap().get() as i32;
let mut current_end_site = first_record.alignment_end().unwrap().unwrap().get() as i32;
if current_start_site < 1 {
current_start_site = 1;
}
while coordinate_position < current_start_site {
coordinate_position += stepsize;
}
for coord in records {
let unwrapped_coord = coord.unwrap().clone();
let mut current_start_site =
unwrapped_coord.alignment_start().unwrap().unwrap().get() as i32;
let new_end_site = unwrapped_coord.alignment_end().unwrap().unwrap().get() as i32;
count += 1;
if current_start_site < 1 {
current_start_site = 1;
}
collected_end_sites.push(new_end_site);
if current_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < current_start_site {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name, bg_prev_coord, coordinate_position, count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
prev_coordinate_value = current_start_site;
}
count += 1;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
count -= 1;
if count < 0 {
count = 0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name, bg_prev_coord, coordinate_position, count
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
drop(writer);
Ok(())
}
pub fn bam_to_bed_no_counts(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
smoothsize: i32,
chromosome_name: &String,
write_fd: Arc<Mutex<PipeWriter>>,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
for coord in records {
let unwrapped_coord = coord.unwrap().clone();
let strand = match unwrapped_coord.flags().is_reverse_complemented() {
true => "-",
false => "+",
};
let flags = unwrapped_coord.flags();
let start_site = unwrapped_coord.alignment_start().unwrap().unwrap().get() as i32;
let end_site = unwrapped_coord.alignment_end().unwrap().unwrap().get() as i32;
let shifted_pos = get_shifted_pos(&flags, start_site - 1, end_site);
let single_line = format!(
"{}\t{}\t{}\t{}\t{}\t{}\n",
chromosome_name,
shifted_pos - smoothsize,
shifted_pos + smoothsize,
"N",
"0",
strand,
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
}
drop(writer);
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub fn variable_shifted_bam_to_bw(
records: &mut Box<Query<noodles::bgzf::reader::Reader<std::fs::File>>>,
chrom_size: i32,
smoothsize: i32,
stepsize: i32,
chromosome_name: &String,
out_sel: &str,
write_fd: Arc<Mutex<PipeWriter>>,
bam_scale: f32,
) -> Result<(), BAMRecordError> {
let mut write_lock = write_fd.lock().unwrap(); let mut writer = BufWriter::new(&mut *write_lock);
let mut coordinate_position = 0;
let mut prev_count: f32 = 0.0;
let mut count: f32 = 0.0;
let mut prev_coordinate_value = 0;
let mut current_end_site: i32;
let mut bg_prev_coord: i32 = 0;
let mut collected_end_sites: Vec<i32> = Vec::new();
let first_record_option = records.next();
let first_record = match first_record_option {
Some(Ok(record)) => record, Some(Err(err)) => {
eprintln!(
"Error reading the first record for {} chrom: {} {:?} Skipping...",
out_sel, chromosome_name, err
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord); }
None => {
eprintln!(
"No records for {} chrom: {} Skipping...",
out_sel, chromosome_name
);
writer.write_all(b"\n").unwrap();
writer.flush().unwrap();
drop(writer);
return Err(BAMRecordError::NoFirstRecord);
}
};
let flags = first_record.flags();
let start_site = first_record.alignment_start().unwrap().unwrap().get() as i32;
let end_site = first_record.alignment_end().unwrap().unwrap().get() as i32;
let shifted_pos = get_shifted_pos(&flags, start_site - 1, end_site);
let original_position = shifted_pos;
let mut adjusted_start_site = (original_position - smoothsize).max(0);
current_end_site = (original_position + smoothsize + 1).min(chrom_size);
while coordinate_position < adjusted_start_site {
coordinate_position += stepsize;
}
for coord in records {
let unwrapped_coord = coord.unwrap().clone();
let flags = unwrapped_coord.flags();
let start_site = unwrapped_coord.alignment_start().unwrap().unwrap().get() as i32;
let end_site = unwrapped_coord.alignment_end().unwrap().unwrap().get() as i32;
let shifted_pos = get_shifted_pos(&flags, start_site - 1, end_site);
let original_position = shifted_pos;
adjusted_start_site = (original_position - smoothsize).max(0);
let new_end_site = (original_position + smoothsize + 1).min(chrom_size);
if new_end_site < current_end_site || coordinate_position > adjusted_start_site {
continue;
} else {
collected_end_sites.push(new_end_site);
}
count += 1.0;
if adjusted_start_site == prev_coordinate_value {
continue;
}
while coordinate_position < adjusted_start_site {
while current_end_site == coordinate_position {
count -= 1.0;
if count < 0.0 {
count = 0.0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0);
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
bg_prev_coord,
coordinate_position,
prev_count / bam_scale
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
prev_coordinate_value = adjusted_start_site;
}
count += 1.0;
if coordinate_position > chrom_size {
eprintln!(
"Chromosome extends beyond defined chromosome in chrom.sizes file {} vs {}",
coordinate_position, chrom_size
);
}
while coordinate_position <= chrom_size {
while current_end_site == coordinate_position {
count -= 1.0;
if count < 0.0 {
count = 0.0;
}
if collected_end_sites.last().is_none() {
current_end_site = 0;
} else {
current_end_site = collected_end_sites.remove(0)
}
}
if count != prev_count {
let single_line = format!(
"{}\t{}\t{}\t{}\n",
chromosome_name,
bg_prev_coord,
coordinate_position,
prev_count / bam_scale
);
writer.write_all(single_line.as_bytes())?;
writer.flush()?;
prev_count = count;
bg_prev_coord = coordinate_position;
}
coordinate_position += 1;
}
drop(writer);
Ok(())
}
fn set_up_file_output(
output_type: &str,
adjusted_start_site: i32,
chromosome_name: &String,
bwfileheader: &str,
stepsize: i32,
out_sel: &str,
std_out_sel: bool,
) -> Result<Box<dyn Write>, io::Error> {
if !std_out_sel {
let filename = format!(
"{}{}_{}.{}",
bwfileheader, chromosome_name, out_sel, output_type
);
let path = std::path::Path::new(&filename).parent().unwrap();
let _ = create_dir_all(path);
let mut file = OpenOptions::new()
.create(true) .append(true) .open(filename)
.unwrap();
match output_type {
"wig" => {
let wig_header = "fixedStep chrom=".to_string()
+ chromosome_name.as_str()
+ " "
+ out_sel
+ "="
+ adjusted_start_site.to_string().as_str()
+ " step="
+ stepsize.to_string().as_str();
file.write_all(wig_header.as_ref()).unwrap();
file.write_all(b"\n").unwrap();
}
"bedgraph" => { }
_ => {
panic!("output type not recognized during file set up for writing!")
}
}
Ok(Box::new(file))
} else {
Ok(Box::new(io::stdout()))
}
}
pub fn get_shifted_pos(flags: &Flags, start_site: i32, end_site: i32) -> i32 {
let shifted_pos: i32;
if flags.bits() & 1 != 0 {
if flags.bits() & 64 != 0 {
if flags.bits() & 16 != 0 {
shifted_pos = end_site + -5;
} else {
shifted_pos = start_site + 4;
}
} else {
if flags.bits() & 16 != 0 {
shifted_pos = end_site + -5;
} else {
shifted_pos = start_site + 4;
}
}
} else {
if flags.bits() & 16 != 0 {
shifted_pos = end_site + -5;
} else {
shifted_pos = start_site + 4;
}
}
shifted_pos
}