// ***************************************************************************
#include <iostream>
+#include <sstream>
#include <string>
#include <vector>
struct CountTool::CountSettings {
// flags
+ bool HasBamIndexFilename;
bool HasInputBamFilename;
bool HasRegion;
// filenames
- std::string InputBamFilename;
- std::string Region;
+ string BamIndexFilename;
+ string InputBamFilename;
+ string Region;
// constructor
CountSettings(void)
- : HasInputBamFilename(false)
+ : HasBamIndexFilename(false)
+ , HasInputBamFilename(false)
, HasRegion(false)
, InputBamFilename(Options::StandardIn())
{ }
, m_settings(new CountSettings)
{
// set program details
- Options::SetProgramInfo("bamtools count", "prints alignment counts for a BAM file", "-in <filename> ");
+ Options::SetProgramInfo("bamtools count", "prints alignment counts for a BAM file", "-in <filename> [-region <REGION> [-index <filename>]]");
// set up options
OptionGroup* IO_Opts = Options::CreateOptionGroup("Input & Output");
- Options::AddValueOption("-in", "BAM filename", "the input BAM file", "", m_settings->HasInputBamFilename, m_settings->InputBamFilename, IO_Opts, Options::StandardIn());
+ Options::AddValueOption("-in", "BAM filename", "the input BAM file", "", m_settings->HasInputBamFilename, m_settings->InputBamFilename, IO_Opts, Options::StandardIn());
+ Options::AddValueOption("-index", "BAM index filename", "the BAM index file", "", m_settings->HasBamIndexFilename, m_settings->BamIndexFilename, IO_Opts);
OptionGroup* FilterOpts = Options::CreateOptionGroup("Filters");
- Options::AddValueOption("-region", "REGION", "genomic region. See README for more details", "", m_settings->HasRegion, m_settings->Region, FilterOpts);
+ Options::AddValueOption("-region", "REGION", "genomic region. Index file is recommended for better performance. See \'bamtools help index\' for more details on creating one", "", m_settings->HasRegion, m_settings->Region, FilterOpts);
}
CountTool::~CountTool(void) {
Options::Parse(argc, argv, 1);
//open our BAM reader
-// BamReader reader;
-// reader.Open(m_settings.InputBamFilename);
+ BamReader reader;
+ reader.Open(m_settings->InputBamFilename);
- // count alignments
- string startChrom;
- string stopChrom;
- int startPos;
- int stopPos;
+ // alignment counter
+ int alignmentCount(0);
+ // set up error handling
+ ostringstream errorStream("");
+ bool foundError(false);
+
+ // if no region specified, count entire file
if ( !m_settings->HasRegion ) {
- cerr << "Counting all alignments " << endl;
- } else {
- if ( Utilities::ParseRegionString(m_settings->Region, startChrom, startPos, stopChrom, stopPos) ) {
- cerr << "Counting only alignments in region " << m_settings->Region << endl;
- cerr << "StartChrom: " << startChrom << endl;
- cerr << "StartPos: " << startPos << endl;
- cerr << "StopChrom: " << stopChrom << endl;
- cerr << "StopPos: " << stopPos << endl;
+ BamAlignment al;
+ while ( reader.GetNextAlignment(al) )
+ ++alignmentCount;
+ }
+
+ // more complicated - region specified
+ else {
+
+ Region region;
+ if ( Utilities::ParseRegionString(m_settings->Region, reader, region) ) {
+
+ // has index, we can jump directly to
+ if ( m_settings->HasBamIndexFilename ) {
+
+ // this is kind of a hack...?
+ // re-open BamReader, this time with the index file
+ reader.Close();
+ reader.Open(m_settings->InputBamFilename, m_settings->BamIndexFilename);
+
+ // attempt Jump(), catch error
+ if ( !reader.Jump(region.StartChromID, region.StartPosition) ) {
+ foundError = true;
+ errorStream << "Could not jump to desired REGION: " << m_settings->Region << endl;
+ }
+ }
+
+ else {
+
+ // read through sequentially, until first overlapping read is found
+ BamAlignment al;
+ bool alignmentFound(false);
+ while( reader.GetNextAlignment(al) ) {
+ if ( (al.RefID == region.StartChromID ) && ( (al.Position + al.Length) >= region.StartPosition) ) {
+ alignmentFound = true;
+ break;
+ }
+ }
+
+ // if overlapping alignment found (not EOF), increment counter
+ if ( alignmentFound) ++ alignmentCount;
+ }
+
+ // -----------------------------
+ // count alignments until stop hit
+
+ if ( !foundError ) {
+ // while valid alignment AND
+ // ( either current ref is before stopRefID OR
+ // current ref stopRefID but we're before stopPos )
+ BamAlignment al;
+ while ( reader.GetNextAlignment(al) && ((al.RefID < region.StopChromID ) || (al.RefID == region.StopChromID && al.Position <= region.StopPosition)) )
+ ++alignmentCount;
+ }
+
+ } else {
+ foundError = true;
+ errorStream << "Could not parse REGION: " << m_settings->Region << endl;
+ errorStream << "Be sure REGION is in valid format (see README) and that coordinates are valid for selected references" << endl;
}
}
- cerr << " from " << m_settings->InputBamFilename << endl;
- cerr << "FEATURE NOT YET IMPLEMENTED!" << endl;
-
+ // print errors OR results
+ if ( foundError )
+ cerr << errorStream.str() << endl;
+ else
+ cout << alignmentCount << endl;
+
// clean & exit
-// reader.Close();
- return 0;
+ reader.Close();
+ return (int)foundError;
}
\ No newline at end of file