1 // ***************************************************************************
2 // BamAlignment.cpp (c) 2009 Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // All rights reserved.
5 // ---------------------------------------------------------------------------
6 // Last modified: 21 March 2011 (DB)
7 // ---------------------------------------------------------------------------
8 // Provides the BamAlignment data structure
9 // ***************************************************************************
11 #include <api/BamAlignment.h>
12 #include <api/BamConstants.h>
13 using namespace BamTools;
24 // internal utility methods
28 /*! \fn bool IsValidSize(const string& tag, const string& type)
31 Checks that tag name & type strings are expected sizes.
32 \a tag should have length
33 \a type should have length 1
35 \param tag BAM tag name
36 \param type BAM tag type-code
38 \return \c true if both \a tag and \a type are correct sizes
40 bool IsValidSize(const string& tag, const string& type) {
41 return (tag.size() == Constants::BAM_TAG_TAGSIZE) &&
42 (type.size() == Constants::BAM_TAG_TYPESIZE);
45 /*! \fn bool SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed)
48 Moves to next available tag in tag data string
50 \param storageType BAM tag type-code that determines how far to move cursor
51 \param pTagData pointer to current position (cursor) in tag string
52 \param numBytesParsed report of how many bytes were parsed (cumulatively)
54 \return \c if storageType was a recognized BAM tag type
55 \post \a pTagData will point to the byte where the next tag data begins.
56 \a numBytesParsed will correspond to the cursor's position in the full TagData string.
58 bool SkipToNextTag(const char storageType, char* &pTagData, unsigned int& numBytesParsed) {
60 switch (storageType) {
62 case (Constants::BAM_TAG_TYPE_ASCII) :
63 case (Constants::BAM_TAG_TYPE_INT8) :
64 case (Constants::BAM_TAG_TYPE_UINT8) :
69 case (Constants::BAM_TAG_TYPE_INT16) :
70 case (Constants::BAM_TAG_TYPE_UINT16) :
75 case (Constants::BAM_TAG_TYPE_FLOAT) :
76 case (Constants::BAM_TAG_TYPE_INT32) :
77 case (Constants::BAM_TAG_TYPE_UINT32) :
82 case (Constants::BAM_TAG_TYPE_STRING) :
83 case (Constants::BAM_TAG_TYPE_HEX) :
88 // increment for null-terminator
95 fprintf(stderr, "BamAlignment ERROR: unknown tag type encountered: [%c]\n", storageType);
103 /*! \fn bool FindTag(const std::string& tag, char* &pTagData, const unsigned int& tagDataLength, unsigned int& numBytesParsed)
106 Searches for requested tag in BAM tag data.
108 \param tag requested 2-character tag name
109 \param pTagData pointer to current position in BamAlignment::TagData
110 \param tagDataLength length of BamAlignment::TagData
111 \param numBytesParsed number of bytes parsed so far
113 \return \c true if found
115 \post If \a tag is found, \a pTagData will point to the byte where the tag data begins.
116 \a numBytesParsed will correspond to the position in the full TagData string.
119 bool FindTag(const std::string& tag,
121 const unsigned int& tagDataLength,
122 unsigned int& numBytesParsed)
125 while ( numBytesParsed < tagDataLength ) {
127 const char* pTagType = pTagData;
128 const char* pTagStorageType = pTagData + 2;
132 // check the current tag, return true on match
133 if ( strncmp(pTagType, tag.c_str(), 2) == 0 )
136 // get the storage class and find the next tag
137 if ( *pTagStorageType == '\0' ) return false;
138 if ( !SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) ) return false;
139 if ( *pTagData == '\0' ) return false;
142 // checked all tags, none match
146 } // namespace Internal
147 } // namespace BamTools
149 /*! \class BamTools::BamAlignment
150 \brief The main BAM alignment data structure.
152 Provides methods to query/modify BAM alignment data fields.
154 /*! \var BamAlignment::Name
157 /*! \var BamAlignment::Length
158 \brief length of query sequence
160 /*! \var BamAlignment::QueryBases
161 \brief 'original' sequence (as reported from sequencing machine)
163 /*! \var BamAlignment::AlignedBases
164 \brief 'aligned' sequence (includes any indels, padding, clipping)
166 /*! \var BamAlignment::Qualities
167 \brief FASTQ qualities (ASCII characters, not numeric values)
169 /*! \var BamAlignment::TagData
170 \brief tag data (use the provided methods to query/modify)
172 /*! \var BamAlignment::RefID
173 \brief ID number for reference sequence
175 /*! \var BamAlignment::Position
176 \brief position (0-based) where alignment starts
178 /*! \var BamAlignment::Bin
179 \brief BAM (standard) index bin number for this alignment
181 /*! \var BamAlignment::MapQuality
182 \brief mapping quality score
184 /*! \var BamAlignment::AlignmentFlag
185 \brief alignment bit-flag (use the provided methods to query/modify)
187 /*! \var BamAlignment::CigarData
188 \brief CIGAR operations for this alignment
190 /*! \var BamAlignment::MateRefID
191 \brief ID number for reference sequence where alignment's mate was aligned
193 /*! \var BamAlignment::MatePosition
194 \brief position (0-based) where alignment's mate starts
196 /*! \var BamAlignment::InsertSize
197 \brief mate-pair insert size
199 /*! \var BamAlignment::Filename
200 \brief name of BAM file which this alignment comes from
203 /*! \fn BamAlignment::BamAlignment(void)
206 BamAlignment::BamAlignment(void)
214 /*! \fn BamAlignment::BamAlignment(const BamAlignment& other)
215 \brief copy constructor
217 BamAlignment::BamAlignment(const BamAlignment& other)
219 , Length(other.Length)
220 , QueryBases(other.QueryBases)
221 , AlignedBases(other.AlignedBases)
222 , Qualities(other.Qualities)
223 , TagData(other.TagData)
225 , Position(other.Position)
227 , MapQuality(other.MapQuality)
228 , AlignmentFlag(other.AlignmentFlag)
229 , CigarData(other.CigarData)
230 , MateRefID(other.MateRefID)
231 , MatePosition(other.MatePosition)
232 , InsertSize(other.InsertSize)
233 , Filename(other.Filename)
234 , SupportData(other.SupportData)
237 /*! \fn BamAlignment::~BamAlignment(void)
240 BamAlignment::~BamAlignment(void) { }
242 /*! \fn bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const std::string& value)
243 \brief Adds a field with string data to the BAM tags.
245 Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
247 \param tag 2-character tag name
248 \param type 1-character tag type (must be "Z" or "H")
249 \param value string data to store
251 \return \c true if the \b new tag was added successfully
253 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
254 for more details on reserved tag names, supported tag types, etc.
256 bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const std::string& value) {
258 // skip if core data not parsed
259 if ( SupportData.HasCoreOnly ) return false;
261 // validate tag/type size & that type is OK for string value
262 if ( !Internal::IsValidSize(tag, type) ) return false;
263 if ( type.at(0) != Constants::BAM_TAG_TYPE_STRING &&
264 type.at(0) != Constants::BAM_TAG_TYPE_HEX )
267 // localize the tag data
268 char* pTagData = (char*)TagData.data();
269 const unsigned int tagDataLength = TagData.size();
270 unsigned int numBytesParsed = 0;
272 // if tag already exists, return false
273 // use EditTag explicitly instead
274 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) )
277 // otherwise, copy tag data to temp buffer
278 string newTag = tag + type + value;
279 const int newTagDataLength = tagDataLength + newTag.size() + 1; // leave room for null-term
280 char originalTagData[newTagDataLength];
281 memcpy(originalTagData, TagData.c_str(), tagDataLength + 1); // '+1' for TagData null-term
284 strcat(originalTagData + tagDataLength, newTag.data()); // removes original null-term, appends newTag + null-term
286 // store temp buffer back in TagData
287 const char* newTagData = (const char*)originalTagData;
288 TagData.assign(newTagData, newTagDataLength);
294 /*! \fn bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const uint32_t& value)
295 \brief Adds a field with unsigned integer data to the BAM tags.
297 Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
299 \param tag 2-character tag name
300 \param type 1-character tag type (must NOT be "f", "Z", or "H")
301 \param value unsigned int data to store
303 \return \c true if the \b new tag was added successfully
304 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
305 for more details on reserved tag names, supported tag types, etc.
307 bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const uint32_t& value) {
309 // skip if core data not parsed
310 if ( SupportData.HasCoreOnly ) return false;
312 // validate tag/type size & that type is OK for uint32_t value
313 if ( !Internal::IsValidSize(tag, type) ) return false;
314 if ( type.at(0) == Constants::BAM_TAG_TYPE_FLOAT ||
315 type.at(0) == Constants::BAM_TAG_TYPE_STRING ||
316 type.at(0) == Constants::BAM_TAG_TYPE_HEX )
319 // localize the tag data
320 char* pTagData = (char*)TagData.data();
321 const unsigned int tagDataLength = TagData.size();
322 unsigned int numBytesParsed = 0;
324 // if tag already exists, return false
325 // use EditTag explicitly instead
326 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) )
329 // otherwise, convert value to string
330 union { uint32_t value; char valueBuffer[sizeof(uint32_t)]; } un;
333 // copy original tag data to temp buffer
334 string newTag = tag + type;
335 const int newTagDataLength = tagDataLength + newTag.size() + 4; // leave room for new integer
336 char originalTagData[newTagDataLength];
337 memcpy(originalTagData, TagData.c_str(), tagDataLength + 1); // '+1' for TagData null-term
340 strcat(originalTagData + tagDataLength, newTag.data());
341 memcpy(originalTagData + tagDataLength + newTag.size(), un.valueBuffer, sizeof(uint32_t));
343 // store temp buffer back in TagData
344 const char* newTagData = (const char*)originalTagData;
345 TagData.assign(newTagData, newTagDataLength);
351 /*! \fn bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const int32_t& value)
352 \brief Adds a field with signed integer data to the BAM tags.
354 Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
356 \param tag 2-character tag name
357 \param type 1-character tag type (must NOT be "f", "Z", or "H")
358 \param value signed int data to store
360 \return \c true if the \b new tag was added successfully
362 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
363 for more details on reserved tag names, supported tag types, etc.
365 bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const int32_t& value) {
366 return AddTag(tag, type, (const uint32_t&)value);
369 /*! \fn bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const float& value)
370 \brief Adds a field with floating-point data to the BAM tags.
372 Does NOT modify an existing tag - use \link BamAlignment::EditTag() \endlink instead.
374 \param tag 2-character tag name
375 \param type 1-character tag type (must NOT be "Z" or "H")
376 \param value float data to store
378 \return \c true if the \b new tag was added successfully
380 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
381 for more details on reserved tag names, supported tag types, etc.
383 bool BamAlignment::AddTag(const std::string& tag, const std::string& type, const float& value) {
385 // skip if core data not parsed
386 if ( SupportData.HasCoreOnly ) return false;
388 // validate tag/type size & that type is OK for float value
389 if ( !Internal::IsValidSize(tag, type) ) return false;
390 if ( type.at(0) == Constants::BAM_TAG_TYPE_STRING ||
391 type.at(0) == Constants::BAM_TAG_TYPE_HEX )
394 // localize the tag data
395 char* pTagData = (char*)TagData.data();
396 const unsigned int tagDataLength = TagData.size();
397 unsigned int numBytesParsed = 0;
399 // if tag already exists, return false
400 // use EditTag explicitly instead
401 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) )
404 // otherwise, convert value to string
405 union { float value; char valueBuffer[sizeof(float)]; } un;
408 // copy original tag data to temp buffer
409 string newTag = tag + type;
410 const int newTagDataLength = tagDataLength + newTag.size() + 4; // leave room for new float
411 char originalTagData[newTagDataLength];
412 memcpy(originalTagData, TagData.c_str(), tagDataLength + 1); // '+1' for TagData null-term
415 strcat(originalTagData + tagDataLength, newTag.data());
416 memcpy(originalTagData + tagDataLength + newTag.size(), un.valueBuffer, sizeof(float));
418 // store temp buffer back in TagData
419 const char* newTagData = (const char*)originalTagData;
420 TagData.assign(newTagData, newTagDataLength);
426 /*! \fn bool BamAlignment::BuildCharData(void)
427 \brief Populates alignment string fields (read name, bases, qualities, tag data).
429 An alignment retrieved using BamReader::GetNextAlignmentCore() lacks this data.
430 Using that method makes parsing much quicker when only positional data is required.
432 However, if you later want to access the character data fields from such an alignment,
433 use this method to populate those fields. Provides ability to do 'lazy evaluation' of
436 \return \c true if character data populated successfully (or was already available to begin with)
438 bool BamAlignment::BuildCharData(void) {
440 // skip if char data already parsed
441 if ( !SupportData.HasCoreOnly )
444 // check system endianness
445 bool IsBigEndian = BamTools::SystemIsBigEndian();
447 // calculate character lengths/offsets
448 const unsigned int dataLength = SupportData.BlockLength - Constants::BAM_CORE_SIZE;
449 const unsigned int seqDataOffset = SupportData.QueryNameLength + (SupportData.NumCigarOperations * 4);
450 const unsigned int qualDataOffset = seqDataOffset + (SupportData.QuerySequenceLength+1)/2;
451 const unsigned int tagDataOffset = qualDataOffset + SupportData.QuerySequenceLength;
452 const unsigned int tagDataLength = dataLength - tagDataOffset;
454 // check offsets to see what char data exists
455 const bool hasSeqData = ( seqDataOffset < dataLength );
456 const bool hasQualData = ( qualDataOffset < dataLength );
457 const bool hasTagData = ( tagDataOffset < dataLength );
459 // set up char buffers
460 const char* allCharData = SupportData.AllCharData.data();
461 const char* seqData = ( hasSeqData ? (((const char*)allCharData) + seqDataOffset) : (const char*)0 );
462 const char* qualData = ( hasQualData ? (((const char*)allCharData) + qualDataOffset) : (const char*)0 );
463 char* tagData = ( hasTagData ? (((char*)allCharData) + tagDataOffset) : (char*)0 );
465 // store alignment name (relies on null char in name as terminator)
466 Name.assign((const char*)(allCharData));
468 // save query sequence
471 QueryBases.reserve(SupportData.QuerySequenceLength);
472 for (unsigned int i = 0; i < SupportData.QuerySequenceLength; ++i) {
473 char singleBase = Constants::BAM_DNA_LOOKUP[ ( (seqData[(i/2)] >> (4*(1-(i%2)))) & 0xf ) ];
474 QueryBases.append(1, singleBase);
478 // save qualities, converting from numeric QV to 'FASTQ-style' ASCII character
481 Qualities.reserve(SupportData.QuerySequenceLength);
482 for (unsigned int i = 0; i < SupportData.QuerySequenceLength; ++i) {
483 char singleQuality = (char)(qualData[i]+33);
484 Qualities.append(1, singleQuality);
488 // clear previous AlignedBases
489 AlignedBases.clear();
491 // if QueryBases has data, build AlignedBases using CIGAR data
492 // otherwise, AlignedBases will remain empty (this case IS allowed)
493 if ( !QueryBases.empty() ) {
495 // resize AlignedBases
496 AlignedBases.reserve(SupportData.QuerySequenceLength);
498 // iterate over CigarOps
500 vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
501 vector<CigarOp>::const_iterator cigarEnd = CigarData.end();
502 for ( ; cigarIter != cigarEnd; ++cigarIter ) {
503 const CigarOp& op = (*cigarIter);
507 // for 'M', 'I' - write bases
508 case (Constants::BAM_CIGAR_MATCH_CHAR) :
509 case (Constants::BAM_CIGAR_INS_CHAR) :
510 AlignedBases.append(QueryBases.substr(k, op.Length));
513 // for 'S' - soft clip, do not write bases
514 // but increment placeholder 'k'
515 case (Constants::BAM_CIGAR_SOFTCLIP_CHAR) :
519 // for 'D' - write gap character
520 case (Constants::BAM_CIGAR_DEL_CHAR) :
521 AlignedBases.append(op.Length, Constants::BAM_DNA_DEL);
524 // for 'P' - write padding character
525 case (Constants::BAM_CIGAR_PAD_CHAR) :
526 AlignedBases.append( op.Length, Constants::BAM_DNA_PAD );
529 // for 'N' - write N's, skip bases in original query sequence
530 case (Constants::BAM_CIGAR_REFSKIP_CHAR) :
531 AlignedBases.append( op.Length, Constants::BAM_DNA_N );
534 // for 'H' - hard clip, do nothing to AlignedBases, move to next op
535 case (Constants::BAM_CIGAR_HARDCLIP_CHAR) :
538 // shouldn't get here
540 fprintf(stderr, "BamAlignment ERROR: invalid CIGAR operation type: %c\n", op.Type);
551 while ( (unsigned int)i < tagDataLength ) {
553 i += Constants::BAM_TAG_TAGSIZE; // skip tag chars (e.g. "RG", "NM", etc.)
554 const char type = tagData[i]; // get tag type at position i
555 ++i; // move i past tag type
559 case(Constants::BAM_TAG_TYPE_ASCII) :
560 case(Constants::BAM_TAG_TYPE_INT8) :
561 case(Constants::BAM_TAG_TYPE_UINT8) :
565 case(Constants::BAM_TAG_TYPE_INT16) :
566 case(Constants::BAM_TAG_TYPE_UINT16) :
567 BamTools::SwapEndian_16p(&tagData[i]);
568 i += sizeof(uint16_t);
571 case(Constants::BAM_TAG_TYPE_FLOAT) :
572 case(Constants::BAM_TAG_TYPE_INT32) :
573 case(Constants::BAM_TAG_TYPE_UINT32) :
574 BamTools::SwapEndian_32p(&tagData[i]);
575 i += sizeof(uint32_t);
578 case(Constants::BAM_TAG_TYPE_HEX) :
579 case(Constants::BAM_TAG_TYPE_STRING) :
580 // no endian swapping necessary for hex-string/string data
581 while (tagData[i]) { ++i; }
582 // increment one more for null terminator
586 // shouldn't get here
588 fprintf(stderr, "BamAlignment ERROR: invalid tag value type: %c\n", type);
594 // store tagData in alignment
595 TagData.resize(tagDataLength);
596 memcpy((char*)TagData.data(), tagData, tagDataLength);
599 // clear the core-only flag
600 SupportData.HasCoreOnly = false;
606 /*! \fn bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const std::string& value)
607 \brief Edits a BAM tag field containing string data.
609 If \a tag does not exist, a new entry is created.
611 \param tag 2-character tag name
612 \param type 1-character tag type (must be "Z" or "H")
613 \param value string data to store
615 \return \c true if the tag was modified/created successfully
617 \sa BamAlignment::RemoveTag()
618 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
619 for more details on reserved tag names, supported tag types, etc.
621 bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const std::string& value) {
623 // skip if core data not parsed
624 if ( SupportData.HasCoreOnly ) return false;
626 // validate tag/type size & that type is OK for string value
627 if ( !Internal::IsValidSize(tag, type) ) return false;
628 if ( type.at(0) != Constants::BAM_TAG_TYPE_STRING &&
629 type.at(0) != Constants::BAM_TAG_TYPE_HEX )
632 // localize the tag data
633 char* pOriginalTagData = (char*)TagData.data();
634 char* pTagData = pOriginalTagData;
635 const unsigned int originalTagDataLength = TagData.size();
637 unsigned int newTagDataLength = 0;
638 unsigned int numBytesParsed = 0;
640 // if tag found, store data in readGroup, return success
641 if ( Internal::FindTag(tag, pTagData, originalTagDataLength, numBytesParsed) ) {
643 // make sure array is more than big enough
644 char newTagData[originalTagDataLength + value.size()];
646 // copy original tag data up til desired tag
647 const unsigned int beginningTagDataLength = numBytesParsed;
648 newTagDataLength += beginningTagDataLength;
649 memcpy(newTagData, pOriginalTagData, numBytesParsed);
651 // copy new VALUE in place of current tag data
652 const unsigned int dataLength = strlen(value.c_str());
653 memcpy(newTagData + beginningTagDataLength, (char*)value.c_str(), dataLength+1 );
655 // skip to next tag (if tag for removal is last, return true)
656 const char* pTagStorageType = pTagData - 1;
657 if ( !Internal::SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) )
660 // copy everything from current tag (the next one after tag for removal) to end
661 const unsigned int skippedDataLength = (numBytesParsed - beginningTagDataLength);
662 const unsigned int endTagOffset = beginningTagDataLength + dataLength + 1;
663 const unsigned int endTagDataLength = originalTagDataLength - beginningTagDataLength - skippedDataLength;
664 memcpy(newTagData + endTagOffset, pTagData, endTagDataLength);
666 // ensure null-terminator
667 newTagData[ endTagOffset + endTagDataLength + 1 ] = 0;
670 TagData.assign(newTagData, endTagOffset + endTagDataLength);
674 // tag not found, attempt AddTag
675 else return AddTag(tag, type, value);
678 /*! \fn bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const uint32_t& value)
679 \brief Edits a BAM tag field containing unsigned integer data.
681 If \a tag does not exist, a new entry is created.
683 \param tag 2-character tag name
684 \param type 1-character tag type (must NOT be "f", "Z", or "H")
685 \param value unsigned integer data to store
687 \return \c true if the tag was modified/created successfully
689 \sa BamAlignment::RemoveTag()
690 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
691 for more details on reserved tag names, supported tag types, etc.
693 bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const uint32_t& value) {
695 // skip if core data not parsed
696 if ( SupportData.HasCoreOnly ) return false;
698 // validate tag/type size & that type is OK for uint32_t value
699 if ( !Internal::IsValidSize(tag, type) ) return false;
700 if ( type.at(0) == Constants::BAM_TAG_TYPE_FLOAT ||
701 type.at(0) == Constants::BAM_TAG_TYPE_STRING ||
702 type.at(0) == Constants::BAM_TAG_TYPE_HEX )
705 // localize the tag data
706 char* pOriginalTagData = (char*)TagData.data();
707 char* pTagData = pOriginalTagData;
708 const unsigned int originalTagDataLength = TagData.size();
710 unsigned int newTagDataLength = 0;
711 unsigned int numBytesParsed = 0;
713 // if tag found, store data in readGroup, return success
714 if ( Internal::FindTag(tag, pTagData, originalTagDataLength, numBytesParsed) ) {
716 // make sure array is more than big enough
717 char newTagData[originalTagDataLength + sizeof(value)];
719 // copy original tag data up til desired tag
720 const unsigned int beginningTagDataLength = numBytesParsed;
721 newTagDataLength += beginningTagDataLength;
722 memcpy(newTagData, pOriginalTagData, numBytesParsed);
724 // copy new VALUE in place of current tag data
725 union { uint32_t value; char valueBuffer[sizeof(uint32_t)]; } un;
727 memcpy(newTagData + beginningTagDataLength, un.valueBuffer, sizeof(uint32_t));
729 // skip to next tag (if tag for removal is last, return true)
730 const char* pTagStorageType = pTagData - 1;
731 if ( !Internal::SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) )
734 // copy everything from current tag (the next one after tag for removal) to end
735 const unsigned int skippedDataLength = (numBytesParsed - beginningTagDataLength);
736 const unsigned int endTagOffset = beginningTagDataLength + sizeof(uint32_t);
737 const unsigned int endTagDataLength = originalTagDataLength - beginningTagDataLength - skippedDataLength;
738 memcpy(newTagData + endTagOffset, pTagData, endTagDataLength);
740 // ensure null-terminator
741 newTagData[ endTagOffset + endTagDataLength + 1 ] = 0;
744 TagData.assign(newTagData, endTagOffset + endTagDataLength);
748 // tag not found, attempt AddTag
749 else return AddTag(tag, type, value);
752 /*! \fn bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const int32_t& value)
753 \brief Edits a BAM tag field containing signed integer data.
755 If \a tag does not exist, a new entry is created.
757 \param tag 2-character tag name
758 \param type 1-character tag type (must NOT be "f", "Z", or "H")
759 \param value signed integer data to store
761 \return \c true if the tag was modified/created successfully
763 \sa BamAlignment::RemoveTag()
764 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
765 for more details on reserved tag names, supported tag types, etc.
767 bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const int32_t& value) {
768 return EditTag(tag, type, (const uint32_t&)value);
771 /*! \fn bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const float& value)
772 \brief Edits a BAM tag field containing floating-point data.
774 If \a tag does not exist, a new entry is created.
776 \param tag 2-character tag name
777 \param type 1-character tag type (must NOT be "Z" or "H")
778 \param value float data to store
780 \return \c true if the tag was modified/created successfully
782 \sa BamAlignment::RemoveTag()
783 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
784 for more details on reserved tag names, supported tag types, etc.
786 bool BamAlignment::EditTag(const std::string& tag, const std::string& type, const float& value) {
788 // skip if core data not parsed
789 if ( SupportData.HasCoreOnly ) return false;
791 // validate tag/type size & that type is OK for float value
792 if ( !Internal::IsValidSize(tag, type) ) return false;
793 if ( type.at(0) == Constants::BAM_TAG_TYPE_STRING ||
794 type.at(0) == Constants::BAM_TAG_TYPE_HEX )
797 // localize the tag data
798 char* pOriginalTagData = (char*)TagData.data();
799 char* pTagData = pOriginalTagData;
800 const unsigned int originalTagDataLength = TagData.size();
802 unsigned int newTagDataLength = 0;
803 unsigned int numBytesParsed = 0;
805 // if tag found, store data in readGroup, return success
806 if ( Internal::FindTag(tag, pTagData, originalTagDataLength, numBytesParsed) ) {
808 // make sure array is more than big enough
809 char newTagData[originalTagDataLength + sizeof(value)];
811 // copy original tag data up til desired tag
812 const unsigned int beginningTagDataLength = numBytesParsed;
813 newTagDataLength += beginningTagDataLength;
814 memcpy(newTagData, pOriginalTagData, numBytesParsed);
816 // copy new VALUE in place of current tag data
817 union { float value; char valueBuffer[sizeof(float)]; } un;
819 memcpy(newTagData + beginningTagDataLength, un.valueBuffer, sizeof(float));
821 // skip to next tag (if tag for removal is last, return true)
822 const char* pTagStorageType = pTagData - 1;
823 if ( !Internal::SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) )
826 // copy everything from current tag (the next one after tag for removal) to end
827 const unsigned int skippedDataLength = (numBytesParsed - beginningTagDataLength);
828 const unsigned int endTagOffset = beginningTagDataLength + sizeof(float);
829 const unsigned int endTagDataLength = originalTagDataLength - beginningTagDataLength - skippedDataLength;
830 memcpy(newTagData + endTagOffset, pTagData, endTagDataLength);
832 // ensure null-terminator
833 newTagData[ endTagOffset + endTagDataLength + 1 ] = 0;
836 TagData.assign(newTagData, endTagOffset + endTagDataLength);
840 // tag not found, attempt AddTag
841 else return AddTag(tag, type, value);
844 /*! \fn bool BamAlignment::GetEditDistance(uint32_t& editDistance) const
845 \brief Retrieves value of edit distance tag ("NM").
847 \deprecated Instead use BamAlignment::GetTag()
849 BamAlignment::GetTag("NM", editDistance);
852 \param editDistance destination for retrieved value
854 \return \c true if found
856 bool BamAlignment::GetEditDistance(uint32_t& editDistance) const {
857 return GetTag("NM", (uint32_t&)editDistance);
860 /*! \fn int BamAlignment::GetEndPosition(bool usePadded = false, bool zeroBased = true) const
861 \brief Calculates alignment end position, based on starting position and CIGAR data.
863 \param usePadded Inserted bases affect reported position. Default is false, so that reported
864 position stays 'sync-ed' with reference coordinates.
865 \param zeroBased Return (BAM standard) 0-based coordinate. Setting this to false can be useful
866 when using BAM data with half-open formats (e.g. BED).
868 \return alignment end position
870 int BamAlignment::GetEndPosition(bool usePadded, bool zeroBased) const {
872 // initialize alignment end to starting position
873 int alignEnd = Position;
875 // iterate over cigar operations
876 vector<CigarOp>::const_iterator cigarIter = CigarData.begin();
877 vector<CigarOp>::const_iterator cigarEnd = CigarData.end();
878 for ( ; cigarIter != cigarEnd; ++cigarIter) {
879 const char cigarType = (*cigarIter).Type;
880 const uint32_t& cigarLength = (*cigarIter).Length;
882 if ( cigarType == Constants::BAM_CIGAR_MATCH_CHAR ||
883 cigarType == Constants::BAM_CIGAR_DEL_CHAR ||
884 cigarType == Constants::BAM_CIGAR_REFSKIP_CHAR )
885 alignEnd += cigarLength;
886 else if ( usePadded && cigarType == Constants::BAM_CIGAR_INS_CHAR )
887 alignEnd += cigarLength;
890 // adjust for zero-based coordinates, if requested
891 if ( zeroBased ) alignEnd -= 1;
897 /*! \fn bool BamAlignment::GetReadGroup(std::string& readGroup) const
898 \brief Retrieves value of read group tag ("RG").
900 \deprecated Instead use BamAlignment::GetTag()
902 BamAlignment::GetTag("RG", readGroup);
905 \param readGroup destination for retrieved value
907 \return \c true if found
909 bool BamAlignment::GetReadGroup(std::string& readGroup) const {
910 return GetTag("RG", readGroup);
913 /*! \fn bool BamAlignment::GetTag(const std::string& tag, std::string& destination) const
914 \brief Retrieves the string value associated with a BAM tag.
916 \param tag 2-character tag name
917 \param destination destination for retrieved value
919 \return \c true if found
921 bool BamAlignment::GetTag(const std::string& tag, std::string& destination) const {
923 // make sure tag data exists
924 if ( SupportData.HasCoreOnly || TagData.empty() )
927 // localize the tag data
928 char* pTagData = (char*)TagData.data();
929 const unsigned int tagDataLength = TagData.size();
930 unsigned int numBytesParsed = 0;
932 // if tag found, store data in readGroup, return success
933 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) ) {
934 const unsigned int dataLength = strlen(pTagData);
936 destination.resize(dataLength);
937 memcpy( (char*)destination.data(), pTagData, dataLength );
941 // tag not found, return failure
945 /*! \fn bool BamAlignment::GetTag(const std::string& tag, uint32_t& destination) const
946 \brief Retrieves the unsigned integer value associated with a BAM tag.
948 \param tag 2-character tag name
949 \param destination destination for retrieved value
951 \return \c true if found
953 bool BamAlignment::GetTag(const std::string& tag, uint32_t& destination) const {
955 // make sure tag data exists
956 if ( SupportData.HasCoreOnly || TagData.empty() )
959 // localize the tag data
960 char* pTagData = (char*)TagData.data();
961 const unsigned int tagDataLength = TagData.size();
962 unsigned int numBytesParsed = 0;
964 // if tag found, determine data byte-length, store data in readGroup, return success
965 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) ) {
967 // determine data byte-length
968 const char type = *(pTagData - 1);
969 int destinationLength = 0;
973 case (Constants::BAM_TAG_TYPE_ASCII) :
974 case (Constants::BAM_TAG_TYPE_INT8) :
975 case (Constants::BAM_TAG_TYPE_UINT8) :
976 destinationLength = 1;
980 case (Constants::BAM_TAG_TYPE_INT16) :
981 case (Constants::BAM_TAG_TYPE_UINT16) :
982 destinationLength = 2;
986 case (Constants::BAM_TAG_TYPE_INT32) :
987 case (Constants::BAM_TAG_TYPE_UINT32) :
988 destinationLength = 4;
991 // unsupported type for integer destination (float or var-length strings)
992 case (Constants::BAM_TAG_TYPE_FLOAT) :
993 case (Constants::BAM_TAG_TYPE_STRING) :
994 case (Constants::BAM_TAG_TYPE_HEX) :
995 fprintf(stderr, "BamAlignment ERROR: cannot store tag of type %c in integer destination\n", type);
1000 fprintf(stderr, "BamAlignment ERROR: unknown tag type encountered: [%c]\n", type);
1004 // store in destination
1006 memcpy(&destination, pTagData, destinationLength);
1010 // tag not found, return failure
1014 /*! \fn bool BamAlignment::GetTag(const std::string& tag, int32_t& destination) const
1015 \brief Retrieves the signed integer value associated with a BAM tag.
1017 \param tag 2-character tag name
1018 \param destination destination for retrieved value
1020 \return \c true if found
1022 bool BamAlignment::GetTag(const std::string& tag, int32_t& destination) const {
1023 return GetTag(tag, (uint32_t&)destination);
1026 /*! \fn bool BamAlignment::GetTag(const std::string& tag, float& destination) const
1027 \brief Retrieves the floating-point value associated with a BAM tag.
1029 \param tag 2-character tag name
1030 \param destination destination for retrieved value
1032 \return \c true if found
1034 bool BamAlignment::GetTag(const std::string& tag, float& destination) const {
1036 // make sure tag data exists
1037 if ( SupportData.HasCoreOnly || TagData.empty() )
1040 // localize the tag data
1041 char* pTagData = (char*)TagData.data();
1042 const unsigned int tagDataLength = TagData.size();
1043 unsigned int numBytesParsed = 0;
1045 // if tag found, determine data byte-length, store data in readGroup, return success
1046 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) ) {
1048 // determine data byte-length
1049 const char type = *(pTagData - 1);
1050 int destinationLength = 0;
1054 case (Constants::BAM_TAG_TYPE_ASCII) :
1055 case (Constants::BAM_TAG_TYPE_INT8) :
1056 case (Constants::BAM_TAG_TYPE_UINT8) :
1057 destinationLength = 1;
1061 case (Constants::BAM_TAG_TYPE_INT16) :
1062 case (Constants::BAM_TAG_TYPE_UINT16) :
1063 destinationLength = 2;
1067 case (Constants::BAM_TAG_TYPE_FLOAT) :
1068 case (Constants::BAM_TAG_TYPE_INT32) :
1069 case (Constants::BAM_TAG_TYPE_UINT32) :
1070 destinationLength = 4;
1073 // unsupported type (var-length strings)
1074 case (Constants::BAM_TAG_TYPE_STRING) :
1075 case (Constants::BAM_TAG_TYPE_HEX) :
1076 fprintf(stderr, "BamAlignment ERROR: cannot store tag of type %c in float destination\n", type);
1081 fprintf(stderr, "BamAlignment ERROR: unknown tag type encountered: [%c]\n", type);
1085 // store in destination
1087 memcpy(&destination, pTagData, destinationLength);
1091 // tag not found, return failure
1095 /*! \fn bool BamAlignment::GetTagType(const std::string& tag, char& type) const
1096 \brief Retrieves the BAM tag type-code associated with requested tag name.
1098 \param tag 2-character tag name
1099 \param type destination for the retrieved (1-character) tag type
1101 \return \c true if found
1103 \sa http://samtools.sourceforge.net/SAM-1.3.pdf
1104 for more details on reserved tag names, supported tag types, etc.
1106 bool BamAlignment::GetTagType(const std::string& tag, char& type) const {
1108 // make sure tag data exists
1109 if ( SupportData.HasCoreOnly || TagData.empty() )
1112 // localize the tag data
1113 char* pTagData = (char*)TagData.data();
1114 const unsigned int tagDataLength = TagData.size();
1115 unsigned int numBytesParsed = 0;
1118 if ( Internal::FindTag(tag, pTagData, tagDataLength, numBytesParsed) ) {
1120 // retrieve tag type code
1121 type = *(pTagData - 1);
1123 // validate that type is a proper BAM tag type
1125 case (Constants::BAM_TAG_TYPE_ASCII) :
1126 case (Constants::BAM_TAG_TYPE_INT8) :
1127 case (Constants::BAM_TAG_TYPE_UINT8) :
1128 case (Constants::BAM_TAG_TYPE_INT16) :
1129 case (Constants::BAM_TAG_TYPE_UINT16) :
1130 case (Constants::BAM_TAG_TYPE_INT32) :
1131 case (Constants::BAM_TAG_TYPE_UINT32) :
1132 case (Constants::BAM_TAG_TYPE_FLOAT) :
1133 case (Constants::BAM_TAG_TYPE_STRING) :
1134 case (Constants::BAM_TAG_TYPE_HEX) :
1139 fprintf(stderr, "BamAlignment ERROR: unknown tag type encountered: [%c]\n", type);
1144 // tag not found, return failure
1148 /*! \fn bool BamAlignment::IsDuplicate(void) const
1149 \return \c true if this read is a PCR duplicate
1151 bool BamAlignment::IsDuplicate(void) const {
1152 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_DUPLICATE) != 0 );
1155 /*! \fn bool BamAlignment::IsFailedQC(void) const
1156 \return \c true if this read failed quality control
1158 bool BamAlignment::IsFailedQC(void) const {
1159 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_QC_FAILED) != 0 );
1162 /*! \fn bool BamAlignment::IsFirstMate(void) const
1163 \return \c true if alignment is first mate on paired-end read
1165 bool BamAlignment::IsFirstMate(void) const {
1166 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_READ_1) != 0 );
1169 /*! \fn bool BamAlignment::IsMapped(void) const
1170 \return \c true if alignment is mapped
1172 bool BamAlignment::IsMapped(void) const {
1173 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_UNMAPPED) == 0 );
1176 /*! \fn bool BamAlignment::IsMateMapped(void) const
1177 \return \c true if alignment's mate is mapped
1179 bool BamAlignment::IsMateMapped(void) const {
1180 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_MATE_UNMAPPED) == 0 );
1183 /*! \fn bool BamAlignment::IsMateReverseStrand(void) const
1184 \return \c true if alignment's mate mapped to reverse strand
1186 bool BamAlignment::IsMateReverseStrand(void) const {
1187 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_MATE_REVERSE_STRAND) != 0 );
1190 /*! \fn bool BamAlignment::IsPaired(void) const
1191 \return \c true if alignment part of paired-end read
1193 bool BamAlignment::IsPaired(void) const {
1194 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_PAIRED) != 0 );
1197 /*! \fn bool BamAlignment::IsPrimaryAlignment(void) const
1198 \return \c true if reported position is primary alignment
1200 bool BamAlignment::IsPrimaryAlignment(void) const {
1201 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_SECONDARY) == 0 );
1204 /*! \fn bool BamAlignment::IsProperPair(void) const
1205 \return \c true if alignment is part of read that satisfied paired-end resolution
1207 bool BamAlignment::IsProperPair(void) const {
1208 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_PROPER_PAIR) != 0 );
1211 /*! \fn bool BamAlignment::IsReverseStrand(void) const
1212 \return \c true if alignment mapped to reverse strand
1214 bool BamAlignment::IsReverseStrand(void) const {
1215 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_REVERSE_STRAND) != 0 );
1218 /*! \fn bool BamAlignment::IsSecondMate(void) const
1219 \return \c true if alignment is second mate on read
1221 bool BamAlignment::IsSecondMate(void) const {
1222 return ( (AlignmentFlag & Constants::BAM_ALIGNMENT_READ_2) != 0 );
1225 /*! \fn bool BamAlignment::RemoveTag(const std::string& tag)
1226 \brief Removes field from BAM tags.
1228 \return \c true if tag was removed successfully (or didn't exist before)
1230 bool BamAlignment::RemoveTag(const std::string& tag) {
1232 // BamAlignments fetched using BamReader::GetNextAlignmentCore() are not allowed
1233 // also, return false if no data present to remove
1234 if ( SupportData.HasCoreOnly || TagData.empty() )
1237 // localize the tag data
1238 char* pOriginalTagData = (char*)TagData.data();
1239 char* pTagData = pOriginalTagData;
1240 const unsigned int originalTagDataLength = TagData.size();
1241 unsigned int newTagDataLength = 0;
1242 unsigned int numBytesParsed = 0;
1244 // if tag found, store data in readGroup, return success
1245 if ( Internal::FindTag(tag, pTagData, originalTagDataLength, numBytesParsed) ) {
1247 char newTagData[originalTagDataLength];
1249 // copy original tag data up til desired tag
1251 numBytesParsed -= 3;
1252 const unsigned int beginningTagDataLength = numBytesParsed;
1253 newTagDataLength += beginningTagDataLength;
1254 memcpy(newTagData, pOriginalTagData, numBytesParsed);
1256 // skip to next tag (if tag for removal is last, return true)
1257 const char* pTagStorageType = pTagData + 2;
1259 numBytesParsed += 3;
1260 if ( !Internal::SkipToNextTag(*pTagStorageType, pTagData, numBytesParsed) )
1263 // copy everything from current tag (the next one after tag for removal) to end
1264 const unsigned int skippedDataLength = (numBytesParsed - beginningTagDataLength);
1265 const unsigned int endTagDataLength = originalTagDataLength - beginningTagDataLength - skippedDataLength;
1266 memcpy(newTagData + beginningTagDataLength, pTagData, endTagDataLength );
1268 // save new tag data
1269 TagData.assign(newTagData, beginningTagDataLength + endTagDataLength);
1273 // tag not found, no removal - return failure
1277 /*! \fn void BamAlignment::SetIsDuplicate(bool ok)
1278 \brief Sets value of "PCR duplicate" flag to \a ok.
1280 void BamAlignment::SetIsDuplicate(bool ok) {
1281 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_DUPLICATE;
1282 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_DUPLICATE;
1285 /*! \fn void BamAlignment::SetIsFailedQC(bool ok)
1286 \brief Sets "failed quality control" flag to \a ok.
1288 void BamAlignment::SetIsFailedQC(bool ok) {
1289 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_QC_FAILED;
1290 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_QC_FAILED;
1293 /*! \fn void BamAlignment::SetIsFirstMate(bool ok)
1294 \brief Sets "alignment is first mate" flag to \a ok.
1296 void BamAlignment::SetIsFirstMate(bool ok) {
1297 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_READ_1;
1298 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_READ_1;
1301 /*! \fn void BamAlignment::SetIsMapped(bool ok)
1302 \brief Sets "alignment is mapped" flag to \a ok.
1304 void BamAlignment::SetIsMapped(bool ok) {
1305 if (ok) AlignmentFlag &= ~Constants::BAM_ALIGNMENT_UNMAPPED;
1306 else AlignmentFlag |= Constants::BAM_ALIGNMENT_UNMAPPED;
1309 /*! \fn void BamAlignment::SetIsMateMapped(bool ok)
1310 \brief Sets "alignment's mate is mapped" flag to \a ok.
1312 void BamAlignment::SetIsMateMapped(bool ok) {
1313 if (ok) AlignmentFlag &= ~Constants::BAM_ALIGNMENT_MATE_UNMAPPED;
1314 else AlignmentFlag |= Constants::BAM_ALIGNMENT_MATE_UNMAPPED;
1317 /*! \fn void BamAlignment::SetIsMateUnmapped(bool ok)
1318 \brief Complement of using SetIsMateMapped().
1319 \deprecated For sake of symmetry with the query methods
1320 \sa IsMateMapped(), SetIsMateMapped()
1322 void BamAlignment::SetIsMateUnmapped(bool ok) {
1323 SetIsMateMapped(!ok);
1326 /*! \fn void BamAlignment::SetIsMateReverseStrand(bool ok)
1327 \brief Sets "alignment's mate mapped to reverse strand" flag to \a ok.
1329 void BamAlignment::SetIsMateReverseStrand(bool ok) {
1330 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_MATE_REVERSE_STRAND;
1331 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_MATE_REVERSE_STRAND;
1334 /*! \fn void BamAlignment::SetIsPaired(bool ok)
1335 \brief Sets "alignment part of paired-end read" flag to \a ok.
1337 void BamAlignment::SetIsPaired(bool ok) {
1338 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_PAIRED;
1339 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_PAIRED;
1342 /*! \fn void BamAlignment::SetIsPrimaryAlignment(bool ok)
1343 \brief Sets "position is primary alignment" flag to \a ok.
1345 void BamAlignment::SetIsPrimaryAlignment(bool ok) {
1346 if (ok) AlignmentFlag &= ~Constants::BAM_ALIGNMENT_SECONDARY;
1347 else AlignmentFlag |= Constants::BAM_ALIGNMENT_SECONDARY;
1350 /*! \fn void BamAlignment::SetIsProperPair(bool ok)
1351 \brief Sets "alignment is part of read that satisfied paired-end resolution" flag to \a ok.
1353 void BamAlignment::SetIsProperPair(bool ok) {
1354 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_PROPER_PAIR;
1355 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_PROPER_PAIR;
1358 /*! \fn void BamAlignment::SetIsReverseStrand(bool ok)
1359 \brief Sets "alignment mapped to reverse strand" flag to \a ok.
1361 void BamAlignment::SetIsReverseStrand(bool ok) {
1362 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_REVERSE_STRAND;
1363 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_REVERSE_STRAND;
1366 /*! \fn void BamAlignment::SetIsSecondaryAlignment(bool ok)
1367 \brief Complement of using SetIsPrimaryAlignment().
1368 \deprecated For sake of symmetry with the query methods
1369 \sa IsPrimaryAlignment(), SetIsPrimaryAlignment()
1371 void BamAlignment::SetIsSecondaryAlignment(bool ok) {
1372 SetIsPrimaryAlignment(!ok);
1375 /*! \fn void BamAlignment::SetIsSecondMate(bool ok)
1376 \brief Sets "alignment is second mate on read" flag to \a ok.
1378 void BamAlignment::SetIsSecondMate(bool ok) {
1379 if (ok) AlignmentFlag |= Constants::BAM_ALIGNMENT_READ_2;
1380 else AlignmentFlag &= ~Constants::BAM_ALIGNMENT_READ_2;
1383 /*! \fn void BamAlignment::SetIsUnmapped(bool ok)
1384 \brief Complement of using SetIsMapped().
1385 \deprecated For sake of symmetry with the query methods
1386 \sa IsMapped(), SetIsMapped()
1388 void BamAlignment::SetIsUnmapped(bool ok) {