/** ** Copyright (c) 2007-2009 Illumina, Inc. ** ** This software is covered by the "Illumina Genome Analyzer Software ** License Agreement" and the "Illumina Source Code License Agreement", ** and certain third party copyright/licenses, and any user of this ** source file is bound by the terms therein (see accompanying files ** Illumina_Genome_Analyzer_Software_License_Agreement.pdf and ** Illumina_Source_Code_License_Agreement.pdf and third party ** copyright/license notices). ** ** This file is part of the Consensus Assessment of Sequence And VAriation ** (CASAVA) software package. ** ** \file Alignment.cpp ** ** \brief Implementation of the alignment-related data types. ** ** \author Come Raczy **/ #include "common/Alignment.hh" #include namespace boost { /** ** \brief Specialization of the lexical_cast from char to Match::Strand. **/ template<> casava::common::Match::Strand lexical_cast(const char &c) { if ('F' == c) return casava::common::Match::Forward; if ('R' == c) return casava::common::Match::Reverse; if (' ' == c) return casava::common::Match::None; if ('N' == c) return casava::common::Match::NM; throw bad_lexical_cast(typeid(casava::common::Match::Strand), typeid(c)); } /** ** \brief Specialization of the lexical_cast from Match::Strand to char. **/ template<> char lexical_cast(const casava::common::Match::Strand &s) { if (casava::common::Match::None == s) return ' '; if (casava::common::Match::Forward == s) return 'F'; if (casava::common::Match::Reverse == s) return 'R'; if (casava::common::Match::NM == s) return 'N'; throw bad_lexical_cast(typeid(char), typeid(s)); } } namespace casava { namespace common { Match::Match(const std::string &chromosome, const std::string &contig, long position, Strand strand, bool isValid) : chromosome_(chromosome) , contig_(contig) , position_(position) , strand_(strand) , isValid_(isValid) { } Match::Match(const Match &match) : chromosome_(match.chromosome_) , contig_(match.contig_) , position_(match.position_) , strand_(match.strand_) , isValid_(match.isValid_) { } Match &Match::operator=(const Match &match) { if (&match != this) { chromosome_ = match.chromosome_; contig_ = match.contig_; position_ = match.position_; strand_ = match.strand_; isValid_ = match.isValid_; } return *this; } bool Match::operator==(const Match &match) const { return this == &match || (match.chromosome_ == chromosome_ && match.contig_ == contig_ && match.position_ == position_ && match.strand_ == strand_ && match.isValid_ == isValid_); } bool Match::operator!=(const Match &match) const { return !(*this == match); } bool Match::getValidity() const { return isValid_; } std::ostream &operator<<(std::ostream &os, const Match &match) { os << match.getChromosome() << '\t' << match.getContig() << '\t'; if (match.isValid_) { os << match.getPosition() << '\t'; // BF457 - field should be "" and not space in the no-match case if (match.getStrand() != casava::common::Match::None ) os << boost::lexical_cast(match.getStrand()); } else { os << '\t'; } return os; } std::istream &operator>>(std::istream &is, Match &match) { // Partner Chromosome may be blank because :- // (a) single read // (b) paired read and chromosomes match // (c) paired read and no partner match match.chromosome_.clear(); if (is.peek() != '\t') { is >> match.chromosome_; } is.ignore(); // Contig may be blank because :- // (a) chromosome is not split into contigs // (b) no match // (c) Partner Config and read is single match.contig_.clear(); if (is.peek() != '\t') { is >> match.contig_; } is.ignore(); // Check that there is a position rather than a blank. match.position_ = 0; match.isValid_ = (is.peek() != '\t'); if (match.isValid_) { is >> match.position_; } is.ignore(); // Expect a strand direction only if there was a position. match.strand_ = Match::None; if (match.isValid_ && (is.peek() != '\t')) { char strand='F'; is >> strand; match.strand_ = boost::lexical_cast(strand); } return is; } Alignment::Alignment(const Sequence &sequence, const casava::common::Match &readMatch, const std::string &matchDescriptor, int singleReadScore, const casava::common::Match &partnerMatch, int pairedReadScore, bool isPaired) : Sequence(sequence), readMatch_(readMatch), matchDescriptor_(matchDescriptor), singleReadScore_(singleReadScore), partnerMatch_(partnerMatch), pairedReadScore_(pairedReadScore), isPaired_(isPaired) { } Alignment::Alignment(const Alignment &alignment) : Sequence(alignment.getSequence()), readMatch_(alignment.readMatch_), matchDescriptor_(alignment.matchDescriptor_), singleReadScore_( alignment.singleReadScore_), partnerMatch_( alignment.partnerMatch_), pairedReadScore_( alignment.pairedReadScore_), isPaired_(alignment.isPaired_) { } Alignment &Alignment::operator=(const Alignment &alignment) { if (&alignment != this) { setSequence(alignment.getSequence()); readMatch_ = alignment.readMatch_; matchDescriptor_ = alignment.matchDescriptor_; singleReadScore_ = alignment.singleReadScore_; partnerMatch_ = alignment.partnerMatch_; pairedReadScore_ = alignment.pairedReadScore_; isPaired_ = alignment.isPaired_; } return *this; } bool Alignment::operator ==(const Alignment &alignment) const { return &alignment == this || (alignment.getSequence() == getSequence() && alignment.readMatch_ == readMatch_ && alignment.matchDescriptor_ == matchDescriptor_ && alignment.singleReadScore_ == singleReadScore_ && alignment.partnerMatch_ == partnerMatch_ && alignment.pairedReadScore_ == pairedReadScore_ && alignment.isPaired_ == isPaired_); } bool Alignment::operator !=(const Alignment &alignment) const { return !(alignment == *this); } std::ostream &operator<<(std::ostream &os, const Alignment &alignment) { /** ** The export file have a specific format which prevents us from using the ** output format readily defined for a Sequence. **/ os << static_cast (alignment.getSequence()) << '\t' << alignment.getMatch() << '\t' << alignment.getMatchDescriptor() << '\t' << alignment.getSingleReadScore() << '\t'; if (alignment.isPaired_) { os << alignment.getPairedReadScore() << '\t' << alignment.getPartnerMatch() << '\t'; } else { os << "\t\t\t\t\t"; } return os << (alignment.getSequence().getPassed() ? "Y" : "N") << '\n'; } std::istream &operator>>(std::istream &is, Alignment &alignment) { /** ** The export file have a specific format which prevents us from using the ** input format readily defined for a Sequence. **/ if (is >> static_cast (alignment)) { is.ignore(); is >> alignment.readMatch_; is.ignore(); if (is.peek() != '\t') { is >> alignment.matchDescriptor_; } is.ignore(); if (is.peek() != '\t') { is >> alignment.singleReadScore_; } is.ignore(); // Use presence of some character other than the next tab as an // indication of a non-blank paired read score and hence a paired read // for output purposes. According to the doc this score would also be // blank if no partner match was found, which is equivalent to single // read for output. if (is.peek() != '\t') { is >> alignment.pairedReadScore_; alignment.isPaired_ = true; } is.ignore(); is >> alignment.partnerMatch_; is.ignore(); bool passed = false; getBool<'Y', 'N'> (is, passed); alignment.setPassed(passed); is.ignore(); // the delimiter for the end of the sequence } return is; } } // namespace common } // namespace casava