lib.rs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. use anyhow::{Context, Ok, Result};
  2. use rust_htslib::{bam, bam::Read};
  3. use average::Mean;
  4. pub fn get_hts_nt_pileup(
  5. bam: &mut rust_htslib::bam::IndexedReader,
  6. chr: &str,
  7. start: i32,
  8. with_next_ins: bool,
  9. ) -> Result<Vec<u8>> {
  10. let stop = start + 1;
  11. let mut bases = Vec::new();
  12. bam.fetch((chr, start, stop))?;
  13. let mut bam_pileup = Vec::new();
  14. for p in bam.pileup() {
  15. let pileup = p.context(format!(
  16. "Can't pilup bam at position {}:{}-{}",
  17. chr, start, stop
  18. ))?;
  19. let position = pileup.pos() as i32;
  20. if position == start {
  21. for alignment in pileup.alignments() {
  22. match alignment.indel() {
  23. bam::pileup::Indel::Ins(_len) => bam_pileup.push(b'I'),
  24. bam::pileup::Indel::Del(_len) => bam_pileup.push(b'D'),
  25. _ => {
  26. let record = alignment.record();
  27. if record.seq_len() > 0 {
  28. if let Some(b) = hts_base_at(&record, start as u32, with_next_ins)? {
  29. bases.push(b);
  30. }
  31. } else {
  32. if alignment.is_del() {
  33. bases.push(b'D');
  34. }
  35. }
  36. }
  37. }
  38. }
  39. }
  40. }
  41. Ok(bases)
  42. }
  43. pub fn hts_base_at(
  44. record: &rust_htslib::bam::record::Record,
  45. at_pos: u32,
  46. with_next_ins: bool,
  47. ) -> Result<Option<u8>> {
  48. use rust_htslib::bam::record::Cigar;
  49. let cigar = record.cigar();
  50. let seq = record.seq();
  51. let pos = cigar.pos() as u32;
  52. let mut read_i = 0u32;
  53. let at_pos = at_pos - 1;
  54. let mut ref_pos = pos;
  55. if ref_pos > at_pos {
  56. return Ok(None);
  57. }
  58. for (id, op) in cigar.iter().enumerate() {
  59. let (add_read, add_ref) = match *op {
  60. Cigar::Match(len) | Cigar::Equal(len) | Cigar::Diff(len) => (len, len),
  61. Cigar::Ins(len) => (len, 0),
  62. Cigar::Del(len) => (0, len),
  63. Cigar::RefSkip(len) => (0, len),
  64. Cigar::SoftClip(len) => (len, 0),
  65. Cigar::HardClip(_) | Cigar::Pad(_) => (0, 0),
  66. };
  67. // If at the end of the op len and next op is Ins return I
  68. if with_next_ins && ref_pos + add_read == at_pos + 1 {
  69. if let Some(Cigar::Ins(_)) = cigar.get(id + 1) {
  70. return Ok(Some(b'I'));
  71. }
  72. }
  73. if ref_pos + add_ref > at_pos {
  74. // Handle deletions directly
  75. if let Cigar::Del(_) = *op {
  76. return Ok(Some(b'D'));
  77. } else if let Cigar::RefSkip(_) = op {
  78. return Ok(None);
  79. } else {
  80. let diff = at_pos - ref_pos;
  81. let p = read_i + diff;
  82. return Ok(Some(seq[p as usize]));
  83. }
  84. }
  85. read_i += add_read;
  86. ref_pos += add_ref;
  87. }
  88. Ok(None)
  89. }
  90. pub fn get_n_start(
  91. bam: &mut rust_htslib::bam::IndexedReader,
  92. chr: &str,
  93. start: i32,
  94. stop: i32,
  95. ) -> Result<usize> {
  96. bam.fetch((chr, start, stop))?;
  97. // let mut start_positions = Vec::new();
  98. let mut n_start = 0;
  99. for read in bam.records() {
  100. let record = read.context(format!("eRR"))?;
  101. let rstart = record.pos() as i32;
  102. if rstart >= start && rstart < stop {
  103. if record.mapq() > 40 {
  104. n_start += 1;
  105. }
  106. // start_positions.push(rstart);
  107. }
  108. }
  109. Ok(n_start)
  110. // Ok(start_positions.len())
  111. }
  112. pub fn range_depths(
  113. bam: &mut rust_htslib::bam::IndexedReader,
  114. chr: &str,
  115. start: i32,
  116. stop: i32,
  117. ) -> Result<Vec<u32>> {
  118. bam.fetch((chr, start, stop))?;
  119. let mut depths = Vec::with_capacity((stop - start) as usize);
  120. depths.fill(0);
  121. for p in bam.pileup() {
  122. let pileup = p.context(format!("eRR"))?;
  123. let rstart = pileup.pos() as i32;
  124. if rstart >= start && rstart < stop {
  125. // depths.push(pileup.depth());
  126. let v = depths.get_mut((rstart - start) as usize).context(format!("Errrr {}", rstart - start))?;
  127. *v = pileup.depth();
  128. } else if rstart >= stop {
  129. break;
  130. }
  131. }
  132. Ok(depths)
  133. }