]> git.donarmstrong.com Git - bamtools.git/blob - BamAux.h
Updated BamAux
[bamtools.git] / BamAux.h
1 // ***************************************************************************\r
2 // BamAux.h (c) 2009 Derek Barnett, Michael Strömberg\r
3 // Marth Lab, Department of Biology, Boston College\r
4 // All rights reserved.\r
5 // ---------------------------------------------------------------------------\r
6 // Last modified: 8 December 2009 (DB)\r
7 // ---------------------------------------------------------------------------\r
8 // Provides the basic constants, data structures, etc. for using BAM files\r
9 // ***************************************************************************\r
10 \r
11 #ifndef BAMAUX_H\r
12 #define BAMAUX_H\r
13 \r
14 // C inclues\r
15 #include <cstdlib>\r
16 #include <cstring>\r
17 \r
18 // C++ includes\r
19 #include <exception>\r
20 #include <map>\r
21 #include <string>\r
22 #include <utility>\r
23 #include <vector>\r
24 \r
25 namespace BamTools {\r
26 \r
27 // BAM constants\r
28 const int BAM_CORE_SIZE   = 32;\r
29 const int BAM_CMATCH      = 0;\r
30 const int BAM_CINS        = 1;\r
31 const int BAM_CDEL        = 2;\r
32 const int BAM_CREF_SKIP   = 3;\r
33 const int BAM_CSOFT_CLIP  = 4;\r
34 const int BAM_CHARD_CLIP  = 5;\r
35 const int BAM_CPAD        = 6;\r
36 const int BAM_CIGAR_SHIFT = 4;\r
37 const int BAM_CIGAR_MASK  = ((1 << BAM_CIGAR_SHIFT) - 1);\r
38 \r
39 // BAM index constants\r
40 const int MAX_BIN           = 37450;    // =(8^6-1)/7+1\r
41 const int BAM_MIN_CHUNK_GAP = 32768;\r
42 const int BAM_LIDX_SHIFT    = 14;\r
43 \r
44 // Explicit variable sizes\r
45 const int BT_SIZEOF_INT = 4;\r
46 \r
47 struct CigarOp;\r
48 \r
49 struct BamAlignment {\r
50 \r
51     // Queries against alignment flag\r
52     public:\r
53         // Returns true if this read is a PCR duplicate (determined by external app)\r
54         bool IsDuplicate(void) const { return ( (AlignmentFlag & DUPLICATE) != 0 ); }\r
55         // Returns true if this read failed quality control (determined by external app)\r
56         bool IsFailedQC(void) const { return ( (AlignmentFlag & QC_FAILED) != 0 ); }\r
57         // Returns true if alignment is first mate on read\r
58         bool IsFirstMate(void) const { return ( (AlignmentFlag & READ_1) != 0 ); }\r
59         // Returns true if alignment is mapped\r
60         bool IsMapped(void) const { return ( (AlignmentFlag & UNMAPPED) == 0 ); }\r
61         // Returns true if alignment's mate is mapped\r
62         bool IsMateMapped(void) const { return ( (AlignmentFlag & MATE_UNMAPPED) == 0 ); }\r
63         // Returns true if alignment's mate mapped to reverse strand\r
64         bool IsMateReverseStrand(void) const { return ( (AlignmentFlag & MATE_REVERSE)  != 0 ); }\r
65         // Returns true if alignment part of paired-end read\r
66         bool IsPaired(void) const { return ( (AlignmentFlag & PAIRED) != 0 ); }\r
67         // Returns true if this position is primary alignment (determined by external app)\r
68         bool IsPrimaryAlignment(void) const  { return ( (AlignmentFlag & SECONDARY) == 0 ); }\r
69         // Returns true if alignment is part of read that satisfied paired-end resolution (determined by external app)\r
70         bool IsProperPair(void) const { return ( (AlignmentFlag & PROPER_PAIR) != 0 ); }\r
71         // Returns true if alignment mapped to reverse strand\r
72         bool IsReverseStrand(void) const { return ( (AlignmentFlag & REVERSE) != 0 ); }\r
73         // Returns true if alignment is second mate on read\r
74         bool IsSecondMate(void) const { return ( (AlignmentFlag & READ_2) != 0 ); }\r
75 \r
76     public:\r
77 \r
78         // get "RG" tag data\r
79         bool GetReadGroup(std::string& readGroup) const {\r
80 \r
81             if ( TagData.empty() ) { return false; }\r
82 \r
83             // localize the tag data\r
84             char* pTagData = (char*)TagData.data();\r
85             const unsigned int tagDataLen = TagData.size();\r
86             unsigned int numBytesParsed = 0;\r
87 \r
88             bool foundReadGroupTag = false;\r
89             while( numBytesParsed < tagDataLen ) {\r
90 \r
91                 const char* pTagType = pTagData;\r
92                 const char* pTagStorageType = pTagData + 2;\r
93                 pTagData       += 3;\r
94                 numBytesParsed += 3;\r
95 \r
96                 // check the current tag\r
97                 if ( std::strncmp(pTagType, "RG", 2) == 0 ) {\r
98                     foundReadGroupTag = true;\r
99                     break;\r
100                 }\r
101 \r
102                 // get the storage class and find the next tag\r
103                 SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
104             }\r
105 \r
106             // return if the read group tag was not present\r
107             if ( !foundReadGroupTag ) { return false; }\r
108 \r
109             // assign the read group\r
110             const unsigned int readGroupLen = std::strlen(pTagData);\r
111             readGroup.resize(readGroupLen);\r
112             std::memcpy( (char*)readGroup.data(), pTagData, readGroupLen );\r
113             return true;\r
114         }\r
115 \r
116         // get "NM" tag data - contributed by Aaron Quinlan\r
117         bool GetEditDistance(uint8_t& editDistance) const {\r
118 \r
119             if ( TagData.empty() ) { return false; }\r
120 \r
121             // localize the tag data\r
122             char* pTagData = (char*)TagData.data();\r
123             const unsigned int tagDataLen = TagData.size();\r
124             unsigned int numBytesParsed = 0;\r
125 \r
126             bool foundEditDistanceTag = false;\r
127             while( numBytesParsed < tagDataLen ) {\r
128 \r
129                 const char* pTagType = pTagData;\r
130                 const char* pTagStorageType = pTagData + 2;\r
131                 pTagData       += 3;\r
132                 numBytesParsed += 3;\r
133 \r
134                 // check the current tag\r
135                 if ( strncmp(pTagType, "NM", 2) == 0 ) {\r
136                     foundEditDistanceTag = true;\r
137                     break;\r
138                 }\r
139 \r
140                 // get the storage class and find the next tag\r
141                 SkipToNextTag( *pTagStorageType, pTagData, numBytesParsed );\r
142             }\r
143             // return if the edit distance tag was not present\r
144             if ( !foundEditDistanceTag ) { return false; }\r
145 \r
146             // assign the editDistance value\r
147             memcpy(&editDistance, pTagData, 1);\r
148             return true;\r
149         }\r
150 \r
151     private:\r
152         static void SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed) {\r
153             switch(storageType) {\r
154 \r
155                 case 'A':\r
156                 case 'c':\r
157                 case 'C':\r
158                         ++numBytesParsed;\r
159                         ++pTagData;\r
160                         break;\r
161 \r
162                 case 's':\r
163                 case 'S':\r
164                 case 'f':\r
165                         numBytesParsed += 2;\r
166                         pTagData       += 2;\r
167                         break;\r
168 \r
169                 case 'i':\r
170                 case 'I':\r
171                         numBytesParsed += 4;\r
172                         pTagData       += 4;\r
173                         break;\r
174 \r
175                 case 'Z':\r
176                 case 'H':\r
177                         while(*pTagData) {\r
178                             ++numBytesParsed;\r
179                             ++pTagData;\r
180                         }\r
181                         break;\r
182 \r
183                 default:\r
184                         printf("ERROR: Unknown tag storage class encountered: [%c]\n", *pTagData);\r
185                         exit(1);\r
186             }\r
187         }\r
188 \r
189     // Data members\r
190     public:\r
191         std::string  Name;              // Read name\r
192         int32_t      Length;            // Query length\r
193         std::string  QueryBases;        // 'Original' sequence (as reported from sequencing machine)\r
194         std::string  AlignedBases;      // 'Aligned' sequence (includes any indels, padding, clipping)\r
195         std::string  Qualities;         // FASTQ qualities (ASCII characters, not numeric values)\r
196         std::string  TagData;           // Tag data (accessor methods will pull the requested information out)\r
197         int32_t      RefID;             // ID number for reference sequence\r
198         int32_t      Position;          // Position (0-based) where alignment starts\r
199         uint16_t     Bin;               // Bin in BAM file where this alignment resides\r
200         uint16_t     MapQuality;        // Mapping quality score\r
201         uint32_t     AlignmentFlag;     // Alignment bit-flag - see Is<something>() methods for available queries\r
202         std::vector<CigarOp> CigarData; // CIGAR operations for this alignment\r
203         int32_t      MateRefID;         // ID number for reference sequence where alignment's mate was aligned\r
204         int32_t      MatePosition;      // Position (0-based) where alignment's mate starts\r
205         int32_t      InsertSize;        // Mate-pair insert size\r
206 \r
207     // Alignment flag query constants\r
208     private:\r
209         enum { PAIRED        = 1,\r
210                PROPER_PAIR   = 2,\r
211                UNMAPPED      = 4,\r
212                MATE_UNMAPPED = 8,\r
213                REVERSE       = 16,\r
214                MATE_REVERSE  = 32,\r
215                READ_1        = 64,\r
216                READ_2        = 128,\r
217                SECONDARY     = 256,\r
218                QC_FAILED     = 512,\r
219                DUPLICATE     = 1024\r
220              };\r
221 };\r
222 \r
223 // ----------------------------------------------------------------\r
224 // Auxiliary data structs & typedefs\r
225 \r
226 struct CigarOp {\r
227     char     Type;   // Operation type (MIDNSHP)\r
228     uint32_t Length; // Operation length (number of bases)\r
229 };\r
230 \r
231 struct RefData {\r
232     // data members\r
233     std::string RefName;          // Name of reference sequence\r
234     int         RefLength;        // Length of reference sequence\r
235     bool        RefHasAlignments; // True if BAM file contains alignments mapped to reference sequence\r
236     // constructor\r
237     RefData(void)\r
238         : RefLength(0)\r
239         , RefHasAlignments(false)\r
240     { }\r
241 };\r
242 \r
243 typedef std::vector<RefData> RefVector;\r
244 typedef std::vector<BamAlignment> BamAlignmentVector;\r
245 \r
246 // ----------------------------------------------------------------\r
247 // Indexing structs & typedefs\r
248 \r
249 struct Chunk {\r
250     // data members\r
251     uint64_t Start;\r
252     uint64_t Stop;\r
253     // constructor\r
254     Chunk(const uint64_t& start = 0, const uint64_t& stop = 0)\r
255         : Start(start)\r
256         , Stop(stop)\r
257     { }\r
258 };\r
259 \r
260 inline\r
261 bool ChunkLessThan(const Chunk& lhs, const Chunk& rhs) {\r
262     return lhs.Start < rhs.Start;\r
263 }\r
264 \r
265 typedef std::vector<Chunk> ChunkVector;\r
266 typedef std::map<uint32_t, ChunkVector> BamBinMap;\r
267 typedef std::vector<uint64_t> LinearOffsetVector;\r
268 \r
269 struct ReferenceIndex {\r
270     // data members\r
271     BamBinMap Bins;\r
272     LinearOffsetVector Offsets;\r
273     // constructor\r
274     ReferenceIndex(const BamBinMap& binMap = BamBinMap(),\r
275                    const LinearOffsetVector& offsets = LinearOffsetVector())\r
276         : Bins(binMap)\r
277         , Offsets(offsets)\r
278     { }\r
279 };\r
280 \r
281 typedef std::vector<ReferenceIndex> BamIndex;\r
282 \r
283 } // namespace BamTools\r
284 \r
285 #endif // BAMAUX_H\r