]> git.donarmstrong.com Git - bamtools.git/blob - src/api/BamMultiReader.cpp
Added explicit merge order to BamMultiReader
[bamtools.git] / src / api / BamMultiReader.cpp
1 // ***************************************************************************
2 // BamMultiReader.cpp (c) 2010 Erik Garrison, Derek Barnett
3 // Marth Lab, Department of Biology, Boston College
4 // ---------------------------------------------------------------------------
5 // Last modified: 14 January 2013 (DB)
6 // ---------------------------------------------------------------------------
7 // Convenience class for reading multiple BAM files.
8 //
9 // This functionality allows applications to work on very large sets of files
10 // without requiring intermediate merge, sort, and index steps for each file
11 // subset. It also improves the performance of our merge system as it
12 // precludes the need to sort merged files.
13 // ***************************************************************************
14
15 #include "api/BamMultiReader.h"
16 #include "api/internal/bam/BamMultiReader_p.h"
17 using namespace BamTools;
18
19 #include <string>
20 #include <vector>
21 using namespace std;
22
23 /*! \class BamTools::BamMultiReader
24     \brief Convenience class for reading multiple BAM files.
25 */
26
27 /*! \enum BamMultiReader::MergeOrder
28     \brief A description of the enum type.
29 */
30 /*! \var BamMultiReader::MergeOrder BamMultiReader::MergeByCoordinate
31     \brief The description of the first enum value.
32 */
33 /*! \var BamMultiReader::MergeOrder BamMultiReader::MergeByName
34     \brief BAM files are
35 */
36
37
38
39 /*! \fn BamMultiReader::BamMultiReader(void)
40     \brief constructor
41 */
42 BamMultiReader::BamMultiReader(void)
43     : d(new Internal::BamMultiReaderPrivate)
44 { }
45
46 /*! \fn BamMultiReader::~BamMultiReader(void)
47     \brief destructor
48 */
49 BamMultiReader::~BamMultiReader(void) {
50     delete d;
51     d = 0;
52 }
53
54 /*! \fn void BamMultiReader::Close(void)
55     \brief Closes all open BAM files.
56
57     Also clears out all header and reference data.
58
59     \sa CloseFile(), IsOpen(), Open(), BamReader::Close()
60 */
61 bool BamMultiReader::Close(void) {
62     return d->Close();
63 }
64
65 /*! \fn void BamMultiReader::CloseFile(const std::string& filename)
66     \brief Closes requested BAM file.
67
68     Leaves any other file(s) open, along with header and reference data.
69
70     \param[in] filename name of specific BAM file to close
71
72     \sa Close(), IsOpen(), Open(), BamReader::Close()
73 */
74 bool BamMultiReader::CloseFile(const std::string& filename) {
75     return d->CloseFile(filename);
76 }
77
78 /*! \fn bool BamMultiReader::CreateIndexes(const BamIndex::IndexType& type)
79     \brief Creates index files for the current BAM files.
80
81     \param[in] type file format to create, see BamIndex::IndexType for available formats
82     \return \c true if index files created OK
83     \sa LocateIndexes(), OpenIndexes(), BamReader::CreateIndex()
84 */
85 bool BamMultiReader::CreateIndexes(const BamIndex::IndexType& type) {
86     return d->CreateIndexes(type);
87 }
88
89 /*! \fn const std::vector<std::string> BamMultiReader::Filenames(void) const
90     \brief Returns list of filenames for all open BAM files.
91
92     Retrieved filenames will contain whatever was passed via Open().
93     If you need full directory paths here, be sure to include them
94     when you open the BAM files.
95
96     \returns names of open BAM files. If no files are open, returns an empty vector.
97     \sa IsOpen(), BamReader::GetFilename()
98 */
99 const std::vector<std::string> BamMultiReader::Filenames(void) const {
100     return d->Filenames();
101 }
102
103 /*! \fn std::string BamMultiReader::GetErrorString(void) const
104     \brief Returns a human-readable description of the last error that occurred
105
106     This method allows elimination of STDERR pollution. Developers of client code
107     may choose how the messages are displayed to the user, if at all.
108
109     \return error description
110 */
111 std::string BamMultiReader::GetErrorString(void) const {
112     return d->GetErrorString();
113 }
114
115 /*! \fn SamHeader BamMultiReader::GetHeader(void) const
116     \brief Returns unified SAM-format header for all files
117
118     \note Modifying the retrieved text does NOT affect the current
119     BAM files. These files have been opened in a read-only mode. However,
120     your modified header text can be used in conjunction with BamWriter
121     to generate a new BAM file with the appropriate header information.
122
123     \returns header data wrapped in SamHeader object
124     \sa GetHeaderText(), BamReader::GetHeader()
125 */
126 SamHeader BamMultiReader::GetHeader(void) const {
127     return d->GetHeader();
128 }
129
130 /*! \fn std::string BamMultiReader::GetHeaderText(void) const
131     \brief Returns unified SAM-format header text for all files
132
133     \note Modifying the retrieved text does NOT affect the current
134     BAM files. These files have been opened in a read-only mode. However,
135     your modified header text can be used in conjunction with BamWriter
136     to generate a new BAM file with the appropriate header information.
137
138     \returns SAM-formatted header text
139     \sa GetHeader(), BamReader::GetHeaderText()
140 */
141 std::string BamMultiReader::GetHeaderText(void) const {
142     return d->GetHeaderText();
143 }
144
145 /*! \fn BamMultiReader::MergeOrder BamMultiReader::GetMergeOrder(void) const
146     \brief Returns curent merge order strategy.
147
148     \returns current merge order enum value
149     \sa BamMultiReader::MergeOrder, SetExplicitMergeOrder()
150 */
151 BamMultiReader::MergeOrder BamMultiReader::GetMergeOrder(void) const {
152     return d->GetMergeOrder();
153 }
154
155 /*! \fn bool BamMultiReader::GetNextAlignment(BamAlignment& alignment)
156     \brief Retrieves next available alignment.
157
158     Equivalent to BamReader::GetNextAlignment() with respect to what is a valid
159     overlapping alignment and what data gets populated.
160
161     This method takes care of determining which alignment actually is 'next'
162     across multiple files, depending on their sort order.
163
164     \param[out] alignment destination for alignment record data
165     \returns \c true if a valid alignment was found
166     \sa GetNextAlignmentCore(), SetExplicitMergeOrder(), SetRegion(), BamReader::GetNextAlignment()
167 */
168 bool BamMultiReader::GetNextAlignment(BamAlignment& nextAlignment) {
169     return d->GetNextAlignment(nextAlignment);
170 }
171
172 /*! \fn bool BamMultiReader::GetNextAlignmentCore(BamAlignment& alignment)
173     \brief Retrieves next available alignment.
174
175     Equivalent to BamReader::GetNextAlignmentCore() with respect to what is a valid
176     overlapping alignment and what data gets populated.
177
178     This method takes care of determining which alignment actually is 'next'
179     across multiple files, depending on their sort order.
180
181     \param[out] alignment destination for alignment record data
182     \returns \c true if a valid alignment was found
183     \sa GetNextAlignment(), SetExplicitMergeOrder(), SetRegion(), BamReader::GetNextAlignmentCore()
184 */
185 bool BamMultiReader::GetNextAlignmentCore(BamAlignment& nextAlignment) {
186     return d->GetNextAlignmentCore(nextAlignment);
187 }
188
189 /*! \fn int BamMultiReader::GetReferenceCount(void) const
190     \brief Returns number of reference sequences.
191     \sa BamReader::GetReferenceCount()
192 */
193 int BamMultiReader::GetReferenceCount(void) const {
194     return d->GetReferenceCount();
195 }
196
197 /*! \fn const RefVector& BamMultiReader::GetReferenceData(void) const
198     \brief Returns all reference sequence entries.
199     \sa RefData, BamReader::GetReferenceData()
200 */
201 const BamTools::RefVector BamMultiReader::GetReferenceData(void) const {
202     return d->GetReferenceData();
203 }
204
205 /*! \fn int BamMultiReader::GetReferenceID(const std::string& refName) const
206     \brief Returns the ID of the reference with this name.
207
208     If \a refName is not found, returns -1.
209
210     \param[in] refName name of reference to look up
211     \sa BamReader::GetReferenceID()
212 */
213 int BamMultiReader::GetReferenceID(const std::string& refName) const {
214     return d->GetReferenceID(refName);
215 }
216
217 /*! \fn bool BamMultiReader::HasIndexes(void) const
218     \brief Returns \c true if all BAM files have index data available.
219     \sa BamReader::HasIndex()
220 */
221 bool BamMultiReader::HasIndexes(void) const {
222     return d->HasIndexes();
223 }
224
225 /*! \fn bool BamMultiReader::HasOpenReaders(void) const
226     \brief Returns \c true if there are any open BAM files.
227 */
228 bool BamMultiReader::HasOpenReaders(void) const {
229     return d->HasOpenReaders();
230 }
231
232 /*! \fn bool BamMultiReader::Jump(int refID, int position)
233     \brief Performs a random-access jump within current BAM files.
234
235     This is a convenience method, equivalent to calling SetRegion()
236     with only a left boundary specified.
237
238     \param[in] refID    ID of reference to jump to
239     \param[in] position (0-based) left boundary
240
241     \returns \c true if jump was successful
242     \sa HasIndex(), BamReader::Jump()
243 */
244
245 bool BamMultiReader::Jump(int refID, int position) {
246     return d->Jump(refID, position);
247 }
248
249 /*! \fn bool BamMultiReader::LocateIndexes(const BamIndex::IndexType& preferredType)
250     \brief Looks for index files that match current BAM files.
251
252     Use this function when you need index files, and perhaps have a
253     preferred index format, but do not depend heavily on which indexes
254     actually get loaded at runtime.
255
256     For each BAM file, this function will defer to your \a preferredType
257     whenever possible. However, if an index file of \a preferredType can
258     not be found, then it will look for any other index file that matches
259     that BAM file.
260
261     An example case would look this:
262     \code
263         BamMultiReader reader;
264
265         // do setup...
266
267         // ensure that all files have an index
268         if ( !reader.LocateIndexes() )      // opens any existing index files that match our BAM files
269             reader.CreateIndexes();         // creates index files for any BAM files that still lack one
270
271         // do interesting stuff using random-access...
272
273     \endcode
274
275     If you want precise control over which index files are loaded, use OpenIndexes()
276     with the desired index filenames. If that function returns false, you can use
277     CreateIndexes() to then build index files of the exact requested format.
278
279     \param[in] preferredType desired index file format, see BamIndex::IndexType for available formats
280     \returns \c true if index files could be found for \b ALL open BAM files
281     \sa BamReader::LocateIndex()
282 */
283 bool BamMultiReader::LocateIndexes(const BamIndex::IndexType& preferredType) {
284     return d->LocateIndexes(preferredType);
285 }
286
287 /*! \fn bool BamMultiReader::Open(const std::vector<std::string>& filenames)
288     \brief Opens BAM files.
289
290     \note Opening BAM files will invalidate any current region set on the multireader.
291     All file pointers will be returned to the beginning of the alignment data. Follow
292     this with Jump() or SetRegion() to establish a region of interest.
293
294     \param[in] filenames list of BAM filenames to open
295     \returns \c true if BAM files were opened successfully
296     \sa Close(), HasOpenReaders(), OpenFile(), OpenIndexes(), BamReader::Open()
297 */
298 bool BamMultiReader::Open(const std::vector<std::string>& filenames) {
299     return d->Open(filenames);
300 }
301
302 /*! \fn bool BamMultiReader::OpenFile(const std::string& filename)
303     \brief Opens a single BAM file.
304
305     Adds another BAM file to multireader "on-the-fly".
306
307     \note Opening a BAM file will invalidate any current region set on the multireader.
308     All file pointers will be returned to the beginning of the alignment data. Follow
309     this with Jump() or SetRegion() to establish a region of interest.
310
311     \param[in] filename BAM filename to open
312     \returns \c true if BAM file was opened successfully
313     \sa Close(), HasOpenReaders(), Open(), OpenIndexes(), BamReader::Open()
314 */
315 bool BamMultiReader::OpenFile(const std::string& filename) {
316     return d->OpenFile(filename);
317 }
318
319 /*! \fn bool BamMultiReader::OpenIndexes(const std::vector<std::string>& indexFilenames)
320     \brief Opens index files for current BAM files.
321
322     \note Currently assumes that index filenames match the order (and number) of
323     BAM files passed to Open().
324
325     \param[in] indexFilenames list of BAM index file names
326     \returns \c true if BAM index file was opened & data loaded successfully
327     \sa LocateIndex(), Open(), SetIndex(), BamReader::OpenIndex()
328 */
329 bool BamMultiReader::OpenIndexes(const std::vector<std::string>& indexFilenames) {
330     return d->OpenIndexes(indexFilenames);
331 }
332
333 /*! \fn bool BamMultiReader::Rewind(void)
334     \brief Returns the internal file pointers to the beginning of alignment records.
335
336     Useful for performing multiple sequential passes through BAM files.
337     Calling this function clears any prior region that may have been set.
338
339     \returns \c true if rewind operation was successful
340     \sa Jump(), SetRegion(), BamReader::Rewind()
341 */
342 bool BamMultiReader::Rewind(void) {
343     return d->Rewind();
344 }
345
346 /*! \fn void BamMultiReader::SetExplicitMergeOrder(BamMultiReader::MergeOrder order)
347     \brief Sets an explicit merge order, regardless of the BAM files' SO header tag.
348
349     The default behavior of the BamMultiReader is to check the SO tag in the BAM files'
350     SAM header text to determine the merge strategy". The merge strategy is used to
351     determine from which BAM file the next alignment should come when either
352     GetNextAlignment() or GetNextAlignmentCore() are called. If files share a
353     'coordinate' or 'queryname' value for this tag, then the merge strategy is
354     selected accordingly. If any of them do not match, or if any fileis marked as
355     'unsorted', then the merge strategy is simply a round-robin.
356
357     This method allows client code to explicitly override the lookup behavior. This
358     method can be useful when you know, for example, that your BAM files are sorted
359     by coordinate but upstream processes did not set the header tag properly.
360
361     \note This method should \bold not be called while reading alignments via
362     GetNextAlignment() or GetNextAlignmentCore(). For proper results, you should
363     call this method before (or immediately after) opening files, rewinding,
364     jumping, etc. but \bold not once alignment fetching has started. There is
365     nothing in the API to prevent you from doing so, but the results may be
366     unexpected.
367
368     \sa BamMultiReader::MergeOrder, GetMergeOrder(), GetNextAlignment(), GetNextAlignmentCore()
369 */
370 void BamMultiReader::SetExplicitMergeOrder(BamMultiReader::MergeOrder order) {
371     d->SetExplicitMergeOrder(order);
372 }
373
374 /*! \fn bool BamMultiReader::SetRegion(const BamRegion& region)
375     \brief Sets a target region of interest
376
377     Equivalent to calling BamReader::SetRegion() on all open BAM files.
378
379     \warning BamRegion now represents a zero-based, HALF-OPEN interval.
380     In previous versions of BamTools (0.x & 1.x) all intervals were treated
381     as zero-based, CLOSED.
382
383     \param[in] region desired region-of-interest to activate
384     \returns \c true if ALL readers set the region successfully
385     \sa HasIndexes(), Jump(), BamReader::SetRegion()
386 */
387 bool BamMultiReader::SetRegion(const BamRegion& region) {
388     return d->SetRegion(region);
389 }
390
391 /*! \fn bool BamMultiReader::SetRegion(const int& leftRefID,
392                                        const int& leftPosition,
393                                        const int& rightRefID,
394                                        const int& rightPosition)
395     \brief Sets a target region of interest
396
397     This is an overloaded function. Equivalent to calling BamReader::SetRegion() on all open BAM files.
398
399     \warning This function now expects a zero-based, HALF-OPEN interval.
400     In previous versions of BamTools (0.x & 1.x) all intervals were treated
401     as zero-based, CLOSED.
402
403     \param[in] leftRefID     referenceID of region's left boundary
404     \param[in] leftPosition  position of region's left boundary
405     \param[in] rightRefID    reference ID of region's right boundary
406     \param[in] rightPosition position of region's right boundary
407
408     \returns \c true if ALL readers set the region successfully
409     \sa HasIndexes(), Jump(), BamReader::SetRegion()
410 */
411 bool BamMultiReader::SetRegion(const int& leftRefID,
412                                const int& leftPosition,
413                                const int& rightRefID,
414                                const int& rightPosition)
415 {
416     return d->SetRegion( BamRegion(leftRefID, leftPosition, rightRefID, rightPosition) );
417 }