source: trunk/yat/omic/BamRead.cc @ 3029

Last change on this file since 3029 was 3029, checked in by Peter, 10 years ago

refs #746. Add docs and throw in aux_del if tag is absent (rather than undefined behaviour)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.7 KB
Line 
1// $Id: BamRead.cc 3029 2013-04-21 01:04:41Z peter $
2
3/*
4  Copyright (C) 2012, 2013 Peter Johansson
5
6  This file is part of the yat library, http://dev.thep.lu.se/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include <config.h>
23
24#include "BamRead.h"
25#include "config_bam.h"
26
27#include YAT_BAM_HEADER
28
29#include "yat/utility/Exception.h"
30
31#include <algorithm>
32#include <cassert>
33#include <sstream>
34
35// bam1_seq_seti is not defined in 0.1.18 (or older), so
36// backport. Code is taken bam.h in version 0.1.19-dev.
37#ifndef bam1_seq_seti
38#define bam1_seq_seti(s, i, c) ( (s)[(i)>>1] = \
39  ((s)[(i)>>1] & 0xf<<(((i)&1)<<2)) | (c)<<((~(i)&1)<<2) )
40#endif
41
42namespace theplu {
43namespace yat {
44namespace omic {
45
46  BamRead::BamRead(void)
47    : bam_(bam_init1())
48  {}
49
50
51  BamRead::BamRead(const BamRead& other)
52    : bam_(bam_dup1(other.bam_))
53  {
54  }
55
56
57  BamRead::~BamRead(void)
58  {
59    bam_destroy1(bam_);
60  }
61
62
63  const BamRead& BamRead::operator=(const BamRead& rhs)
64  {
65    if (bam_!=rhs.bam_)
66      bam_copy1(bam_, rhs.bam_);
67    return *this;
68  }
69
70
71  const uint8_t* BamRead::aux(void) const
72  {
73    assert(bam_);
74    return bam1_aux(bam_);
75  }
76
77
78  const uint8_t* BamRead::aux(const char tag[2]) const
79  {
80    assert(bam_);
81    return bam_aux_get(bam_, tag);
82  }
83
84
85  void BamRead::aux_append(const char tag[2], char type,int len,uint8_t* data)
86  {
87    assert(bam_);
88    bam_aux_append(bam_, tag, type, len, data);
89  }
90
91
92  void BamRead::aux_del(const char tag[2])
93  {
94    assert(bam_);
95    uint8_t* s = bam_aux_get(bam_, tag);
96    if (s)
97      bam_aux_del(bam_, s);
98    std::stringstream msg("BamRead::aux_del: absent tag: ");
99    msg << "'" << tag << "'";
100    throw utility::runtime_error(msg.str());
101  }
102
103
104  int BamRead::aux_size(void) const
105  {
106    assert(bam_);
107    return bam_->l_aux;
108  }
109
110
111  const uint32_t* BamRead::cigar(void) const
112  {
113    return bam1_cigar(bam_);
114  }
115
116
117  uint32_t BamRead::cigar(size_t i) const
118  {
119    assert(i<core().n_cigar);
120    return bam1_cigar(bam_)[i];
121  }
122
123
124  uint32_t BamRead::cigar_op(size_t i) const
125  {
126    assert(i<core().n_cigar);
127    return bam_cigar_op(cigar(i));
128  }
129
130
131  uint32_t BamRead::cigar_oplen(size_t i) const
132  {
133    assert(i<core().n_cigar);
134    return bam_cigar_oplen(cigar(i));
135  }
136
137
138  std::string BamRead::cigar_str(void) const
139  {
140    std::ostringstream os;
141    std::string str = BAM_CIGAR_STR;
142    for (uint32_t i=0; i<core().n_cigar; ++i) {
143      os << bam_cigar_oplen(bam1_cigar(bam_)[i])
144         << str[bam_cigar_op(bam1_cigar(bam_)[i])];
145    }
146    return os.str();
147  }
148
149
150  void BamRead::cigar(const std::vector<uint32_t>& c)
151  {
152    // special case when cigar size is not changed
153    if (c.size() == core().n_cigar) {
154      if (c.size())
155        memcpy(bam1_cigar(bam_), &c[0], 4*c.size());
156      return;
157    }
158
159    int m_data = bam_->m_data;
160    int data_len = bam_->data_len + 4*c.size() - 4*core().n_cigar;
161    // double capacity if needed
162    if (m_data < data_len) {
163      m_data = data_len;
164      kroundup32(m_data);
165    }
166    uint8_t* data = (uint8_t*)calloc(m_data, 1);
167    /*
168      data comes as qname, cigar, rest
169     */
170    // first copy qname
171    memcpy(data, bam_->data, core().l_qname);
172    // copy new cigar
173    if (c.size())
174      // each cigar element is 4 bytes
175      memcpy(data + core().l_qname, &c[0], 4*c.size());
176    // copy remaining data
177    memcpy(data + core().l_qname + 4*c.size(), bam1_seq(bam_),
178           data_len - 4*c.size() - core().l_qname);
179    bam_->m_data = m_data;
180    bam_->data_len = data_len;
181    core().n_cigar = c.size();
182    free(bam_->data);
183    bam_->data = data;
184  }
185
186
187  const bam1_core_t& BamRead::core(void) const
188  { return bam_->core; }
189
190
191  bam1_core_t& BamRead::core(void)
192  { return bam_->core; }
193
194
195  const char* BamRead::name(void) const
196  { return bam1_qname(bam_); }
197
198
199  uint8_t BamRead::qual(size_t i) const
200  { return *(bam1_qual(bam_)+i); }
201
202
203  void BamRead::qual(size_t i, uint8_t q)
204  { *(bam1_qual(bam_)+i)=q; }
205
206
207  std::string BamRead::sequence(void) const
208  {
209    std::string result(sequence_length(), ' ');
210#ifdef HAVE_BAM_NT16_REV_TABLE
211    for (size_t i=0; i<result.size(); ++i)
212      result[i] = bam_nt16_rev_table[sequence(i)];
213#else
214    std::string table = "=ACMGRSVTWYHKDBN";
215    for (size_t i=0; i<result.size(); ++i)
216      result[i] = table[sequence(i)];
217#endif
218    return result;
219  }
220
221
222  void BamRead::sequence(size_t i, uint8_t seq)
223  {
224    assert(bam_);
225    assert(seq < 16);
226    bam1_seq_seti(bam1_seq(bam_), i, seq);
227  }
228
229
230  uint8_t BamRead::sequence(size_t index) const
231  {
232    assert(bam_);
233    return bam1_seqi(bam1_seq(bam_),index);
234  }
235
236
237  uint32_t BamRead::sequence_length(void) const
238  {
239    assert(bam_);
240    return bam_->core.l_qseq;
241  }
242
243
244  int32_t BamRead::pos(void) const
245  {
246    assert(bam_);
247    return bam_->core.pos;
248  }
249
250
251  int32_t BamRead::tid(void) const
252  {
253    assert(bam_);
254    return bam_->core.tid;
255  }
256
257
258  int32_t BamRead::mtid(void) const
259  {
260    assert(bam_);
261    return bam_->core.mtid;
262  }
263
264
265  int32_t BamRead::mpos(void) const
266  {
267    assert(bam_);
268    return bam_->core.mpos;
269  }
270
271
272  int32_t BamRead::end(void) const
273  {
274    assert(bam_);
275    return bam_calend(&core(), bam1_cigar(bam_));
276  }
277
278
279  void BamRead::swap(BamRead& other)
280  {
281    std::swap(bam_, other.bam_);
282  }
283
284
285  void swap(BamRead& lhs, BamRead& rhs)
286  {
287    lhs.swap(rhs);
288  }
289
290  bool same_query_name(const BamRead& lhs, const BamRead& rhs)
291  {
292    if (lhs.core().l_qname != rhs.core().l_qname)
293      return false;
294
295    return std::equal(lhs.name(),
296                      lhs.name() + lhs.core().l_qname,
297                      rhs.name());
298  }
299
300
301  bool soft_clipped(const BamRead& bam)
302  {
303    return left_soft_clipped(bam) || right_soft_clipped(bam);
304  }
305
306
307  uint32_t left_soft_clipped(const BamRead& bam)
308  {
309    for (size_t i=0; i<bam.core().n_cigar; ++i) {
310      if (bam.cigar_op(i) == BAM_CSOFT_CLIP)
311        return bam.cigar_oplen(i);
312      if (bam_cigar_type(bam.cigar_op(i))&1)
313        return 0;
314    }
315    return 0;
316  }
317
318
319  uint32_t right_soft_clipped(const BamRead& bam)
320  {
321    if (bam.core().n_cigar==0)
322      return 0;
323    // right clip can't be at first (most left cigar element)
324    for (size_t i=bam.core().n_cigar-1; i>0; --i) {
325      if (bam.cigar_op(i) == BAM_CSOFT_CLIP)
326        return bam.cigar_oplen(i);
327      if (bam_cigar_type(bam.cigar_op(i))&1)
328        return 0;
329    }
330    return 0;
331  }
332
333
334  bool BamLessPos::operator()(const BamRead& lhs, const BamRead& rhs) const
335  {
336    return lhs.tid() < rhs.tid() ||
337      (lhs.tid() == rhs.tid() && lhs.pos() < rhs.pos());
338  }
339
340
341  bool BamLessEnd::operator()(const BamRead& lhs, const BamRead& rhs) const
342  {
343    return lhs.tid() < rhs.tid() ||
344      (lhs.tid() == rhs.tid() && lhs.end() < rhs.end());
345  }
346
347}}}
Note: See TracBrowser for help on using the repository browser.