|
@@ -34,6 +34,10 @@ pub fn read_bam(input_bam: &Path) -> anyhow::Result<Vec<Record>> {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub fn cp_mod_tags(input_records: &Vec<Record>, output_path: &str) -> anyhow::Result<()> {
|
|
pub fn cp_mod_tags(input_records: &Vec<Record>, output_path: &str) -> anyhow::Result<()> {
|
|
|
|
|
+ // omit tags representing alignement values
|
|
|
|
|
+ let omit_tags = [
|
|
|
|
|
+ b"NM", b"ms", b"AS", b"nn", b"de", b"tp", b"cm", b"s1", b"s2", b"MD", b"rl",
|
|
|
|
|
+ ];
|
|
|
info!("Transferring SAM tags from records to {output_path}");
|
|
info!("Transferring SAM tags from records to {output_path}");
|
|
|
// Read tags from input tags
|
|
// Read tags from input tags
|
|
|
let mut mm_hm = HashMap::new();
|
|
let mut mm_hm = HashMap::new();
|
|
@@ -42,8 +46,7 @@ pub fn cp_mod_tags(input_records: &Vec<Record>, output_path: &str) -> anyhow::Re
|
|
|
for record in input_records {
|
|
for record in input_records {
|
|
|
// let record = record?;
|
|
// let record = record?;
|
|
|
let query_name = String::from_utf8(record.name().to_vec())?;
|
|
let query_name = String::from_utf8(record.name().to_vec())?;
|
|
|
- let u = record.tags();
|
|
|
|
|
- tags_hm.insert(query_name.clone(), u.clone());
|
|
|
|
|
|
|
+ tags_hm.insert(query_name.clone(), record.tags().clone());
|
|
|
if let Some(TagValue::String(value, StringType::String)) = record.tags().get(b"MM") {
|
|
if let Some(TagValue::String(value, StringType::String)) = record.tags().get(b"MM") {
|
|
|
mm_hm.insert(query_name.clone(), value.to_vec());
|
|
mm_hm.insert(query_name.clone(), value.to_vec());
|
|
|
}
|
|
}
|
|
@@ -70,16 +73,36 @@ pub fn cp_mod_tags(input_records: &Vec<Record>, output_path: &str) -> anyhow::Re
|
|
|
let mut record = record.clone();
|
|
let mut record = record.clone();
|
|
|
let record_name = String::from_utf8(record.name().to_vec())?;
|
|
let record_name = String::from_utf8(record.name().to_vec())?;
|
|
|
let tags = record.tags_mut();
|
|
let tags = record.tags_mut();
|
|
|
- if let Some(all) = tags_hm.get(&record_name) {
|
|
|
|
|
- *tags = all.clone();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if let Some(from) = tags_hm.get(&record_name) {
|
|
|
|
|
+ from.iter().filter(|(name, _)| !omit_tags.contains(&name)).for_each(|(name, tag)| {
|
|
|
|
|
+ match tag {
|
|
|
|
|
+ TagValue::Char(v) => tags.push_char(&name, v),
|
|
|
|
|
+ TagValue::Int(v, iv) => match iv {
|
|
|
|
|
+ bam::record::tags::IntegerType::I8 => tags.push_num(&name, v as i8),
|
|
|
|
|
+ bam::record::tags::IntegerType::U8 => tags.push_num(&name, v as u8),
|
|
|
|
|
+ bam::record::tags::IntegerType::I16 => tags.push_num(&name, v as i16),
|
|
|
|
|
+ bam::record::tags::IntegerType::U16 => tags.push_num(&name, v as u16),
|
|
|
|
|
+ bam::record::tags::IntegerType::I32 => tags.push_num(&name, v as i32),
|
|
|
|
|
+ bam::record::tags::IntegerType::U32 => tags.push_num(&name, v as u32),
|
|
|
|
|
+ },
|
|
|
|
|
+ TagValue::Float(v) => tags.push_num(&name, v),
|
|
|
|
|
+ TagValue::String(v, iv) => match iv {
|
|
|
|
|
+ StringType::String => tags.push_string(&name, v),
|
|
|
|
|
+ StringType::Hex => tags.push_hex(&name, v),
|
|
|
|
|
+ },
|
|
|
|
|
+ TagValue::IntArray(arr) => tags.push_array(&name, arr.raw()),
|
|
|
|
|
+ TagValue::FloatArray(arr) => tags.push_array(&name, arr.raw()),
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
// if let Some(mm) = mm_hm.get(&record_name) {
|
|
// if let Some(mm) = mm_hm.get(&record_name) {
|
|
|
// tags.push_string(b"MM", mm)
|
|
// tags.push_string(b"MM", mm)
|
|
|
// }
|
|
// }
|
|
|
// let tags = record.tags_mut();
|
|
// let tags = record.tags_mut();
|
|
|
// if let Some(ml) = ml_hm.get(&record_name) {
|
|
// if let Some(ml) = ml_hm.get(&record_name) {
|
|
|
- // let v = ml.as_bytes();
|
|
|
|
|
- // tags.push_array(b"ML", v);
|
|
|
|
|
|
|
+ // // let v = ml.bytes();
|
|
|
|
|
+ // tags.push_array(b"ML", ml);
|
|
|
// }
|
|
// }
|
|
|
w.write(&record)?;
|
|
w.write(&record)?;
|
|
|
}
|
|
}
|
|
@@ -146,7 +169,7 @@ pub fn create_bam_leave_two_out(input_path: &str) -> anyhow::Result<Vec<PathBuf>
|
|
|
writer.write(record)?;
|
|
writer.write(record)?;
|
|
|
} else {
|
|
} else {
|
|
|
warn!(
|
|
warn!(
|
|
|
- "{} removing {}",
|
|
|
|
|
|
|
+ "{} removing qname {}",
|
|
|
output_path.display(),
|
|
output_path.display(),
|
|
|
String::from_utf8(record.qname().to_vec()).unwrap()
|
|
String::from_utf8(record.qname().to_vec()).unwrap()
|
|
|
);
|
|
);
|
|
@@ -168,14 +191,17 @@ pub fn create_bam_leave_two_out(input_path: &str) -> anyhow::Result<Vec<PathBuf>
|
|
|
// }
|
|
// }
|
|
|
pub fn remap_bam(reference: &str, input_seq: &str, output_bam: &str) -> anyhow::Result<()> {
|
|
pub fn remap_bam(reference: &str, input_seq: &str, output_bam: &str) -> anyhow::Result<()> {
|
|
|
info!("Remaping {input_seq} to {reference} into {output_bam}");
|
|
info!("Remaping {input_seq} to {reference} into {output_bam}");
|
|
|
- // Index the reference
|
|
|
|
|
|
|
+ // Index the reference
|
|
|
let index_output = Command::new("bwa")
|
|
let index_output = Command::new("bwa")
|
|
|
.args(["index", reference])
|
|
.args(["index", reference])
|
|
|
.output()
|
|
.output()
|
|
|
.context("Failed to run bwa index")?;
|
|
.context("Failed to run bwa index")?;
|
|
|
|
|
|
|
|
if !index_output.status.success() {
|
|
if !index_output.status.success() {
|
|
|
- anyhow::bail!("bwa index failed: {}", String::from_utf8_lossy(&index_output.stderr));
|
|
|
|
|
|
|
+ anyhow::bail!(
|
|
|
|
|
+ "bwa index failed: {}",
|
|
|
|
|
+ String::from_utf8_lossy(&index_output.stderr)
|
|
|
|
|
+ );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Prepare the bwa mem command
|
|
// Prepare the bwa mem command
|
|
@@ -184,7 +210,8 @@ pub fn remap_bam(reference: &str, input_seq: &str, output_bam: &str) -> anyhow::
|
|
|
bwa_command.stdout(Stdio::piped());
|
|
bwa_command.stdout(Stdio::piped());
|
|
|
bwa_command.stderr(Stdio::piped());
|
|
bwa_command.stderr(Stdio::piped());
|
|
|
|
|
|
|
|
- let mut bwa_process = bwa_command.spawn()
|
|
|
|
|
|
|
+ let mut bwa_process = bwa_command
|
|
|
|
|
+ .spawn()
|
|
|
.context("Failed to spawn bwa mem command")?;
|
|
.context("Failed to spawn bwa mem command")?;
|
|
|
|
|
|
|
|
// Prepare the samtools sort command
|
|
// Prepare the samtools sort command
|
|
@@ -192,23 +219,28 @@ pub fn remap_bam(reference: &str, input_seq: &str, output_bam: &str) -> anyhow::
|
|
|
samtools_command.args(["sort", "/dev/stdin"]);
|
|
samtools_command.args(["sort", "/dev/stdin"]);
|
|
|
samtools_command.stdin(Stdio::piped());
|
|
samtools_command.stdin(Stdio::piped());
|
|
|
samtools_command.stdout(Stdio::from(
|
|
samtools_command.stdout(Stdio::from(
|
|
|
- std::fs::File::create(output_bam).context("Failed to create output BAM file")?
|
|
|
|
|
|
|
+ std::fs::File::create(output_bam).context("Failed to create output BAM file")?,
|
|
|
));
|
|
));
|
|
|
samtools_command.stderr(Stdio::piped());
|
|
samtools_command.stderr(Stdio::piped());
|
|
|
|
|
|
|
|
- let mut samtools_process = samtools_command.spawn()
|
|
|
|
|
|
|
+ let mut samtools_process = samtools_command
|
|
|
|
|
+ .spawn()
|
|
|
.context("Failed to spawn samtools command")?;
|
|
.context("Failed to spawn samtools command")?;
|
|
|
|
|
|
|
|
// Connect bwa stdout to samtools stdin
|
|
// Connect bwa stdout to samtools stdin
|
|
|
- if let (Some(mut bwa_stdout), Some(mut samtools_stdin)) = (bwa_process.stdout.take(), samtools_process.stdin.take()) {
|
|
|
|
|
- std::thread::spawn(move || {
|
|
|
|
|
- std::io::copy(&mut bwa_stdout, &mut samtools_stdin)
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ if let (Some(mut bwa_stdout), Some(mut samtools_stdin)) =
|
|
|
|
|
+ (bwa_process.stdout.take(), samtools_process.stdin.take())
|
|
|
|
|
+ {
|
|
|
|
|
+ std::thread::spawn(move || std::io::copy(&mut bwa_stdout, &mut samtools_stdin));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Capture stderr from bwa
|
|
// Capture stderr from bwa
|
|
|
let mut bwa_stderr = String::new();
|
|
let mut bwa_stderr = String::new();
|
|
|
- bwa_process.stderr.take().unwrap().read_to_string(&mut bwa_stderr)?;
|
|
|
|
|
|
|
+ bwa_process
|
|
|
|
|
+ .stderr
|
|
|
|
|
+ .take()
|
|
|
|
|
+ .unwrap()
|
|
|
|
|
+ .read_to_string(&mut bwa_stderr)?;
|
|
|
|
|
|
|
|
// Wait for bwa to finish
|
|
// Wait for bwa to finish
|
|
|
let bwa_status = bwa_process.wait().context("Failed to wait for bwa mem")?;
|
|
let bwa_status = bwa_process.wait().context("Failed to wait for bwa mem")?;
|
|
@@ -218,10 +250,16 @@ pub fn remap_bam(reference: &str, input_seq: &str, output_bam: &str) -> anyhow::
|
|
|
|
|
|
|
|
// Capture stderr from samtools
|
|
// Capture stderr from samtools
|
|
|
let mut samtools_stderr = String::new();
|
|
let mut samtools_stderr = String::new();
|
|
|
- samtools_process.stderr.take().unwrap().read_to_string(&mut samtools_stderr)?;
|
|
|
|
|
|
|
+ samtools_process
|
|
|
|
|
+ .stderr
|
|
|
|
|
+ .take()
|
|
|
|
|
+ .unwrap()
|
|
|
|
|
+ .read_to_string(&mut samtools_stderr)?;
|
|
|
|
|
|
|
|
// Wait for samtools to finish
|
|
// Wait for samtools to finish
|
|
|
- let samtools_status = samtools_process.wait().context("Failed to wait for samtools")?;
|
|
|
|
|
|
|
+ let samtools_status = samtools_process
|
|
|
|
|
+ .wait()
|
|
|
|
|
+ .context("Failed to wait for samtools")?;
|
|
|
if !samtools_status.success() {
|
|
if !samtools_status.success() {
|
|
|
anyhow::bail!("samtools sort failed: {}", samtools_stderr);
|
|
anyhow::bail!("samtools sort failed: {}", samtools_stderr);
|
|
|
}
|
|
}
|