Пример #1
0
int Bam2FastQ::execute(int argc, char **argv)
{
    // Extract command line arguments.
    String inFile = "";
    bool readName = false;
    String refFile = "";
    String firstOut = "";
    String secondOut = "";
    String unpairedOut = "";

    bool interleave = false;
    bool noeof = false;
    bool gzip = false;
    bool params = false;

    myOutBase = "";
    myNumMateFailures = 0;
    myNumPairs = 0;
    myNumUnpaired = 0;
    mySplitRG = false;
    myQField = "";
    myNumQualTagErrors = 0;
    myReverseComp = true;
    myRNPlus = false;
    myFirstRNExt = DEFAULT_FIRST_EXT;
    mySecondRNExt = DEFAULT_SECOND_EXT;
    myCompression = InputFile::DEFAULT;

    ParameterList inputParameters;
    BEGIN_LONG_PARAMETERS(longParameterList)
        LONG_PARAMETER_GROUP("Required Parameters")
        LONG_STRINGPARAMETER("in", &inFile)
        LONG_PARAMETER_GROUP("Optional Parameters")
        LONG_PARAMETER("readName", &readName)
        LONG_PARAMETER("splitRG", &mySplitRG)
        LONG_STRINGPARAMETER("qualField", &myQField)
        LONG_PARAMETER("merge", &interleave)
        LONG_STRINGPARAMETER("refFile", &refFile)
        LONG_STRINGPARAMETER("firstRNExt", &myFirstRNExt)
        LONG_STRINGPARAMETER("secondRNExt", &mySecondRNExt)
        LONG_PARAMETER("rnPlus", &myRNPlus)
        LONG_PARAMETER("noReverseComp", &myReverseComp)
        LONG_PARAMETER("gzip", &gzip)
        LONG_PARAMETER("noeof", &noeof)
        LONG_PARAMETER("params", &params)
        LONG_PARAMETER_GROUP("Optional OutputFile Names")
        LONG_STRINGPARAMETER("outBase", &myOutBase)
        LONG_STRINGPARAMETER("firstOut", &firstOut)
        LONG_STRINGPARAMETER("secondOut", &secondOut)
        LONG_STRINGPARAMETER("unpairedOut", &unpairedOut)
        LONG_PHONEHOME(VERSION)
        END_LONG_PARAMETERS();
   
    inputParameters.Add(new LongParameters ("Input Parameters", 
                                            longParameterList));

    // parameters start at index 2 rather than 1.
    inputParameters.Read(argc, argv, 2);

    // If no eof block is required for a bgzf file, set the bgzf file type to 
    // not look for it.
    if(noeof)
    {
        // Set that the eof block is not required.
        BgzfFileType::setRequireEofBlock(false);
    }

    if(gzip)
    {
        myCompression = InputFile::GZIP;
    }

    // Check to see if the in file was specified, if not, report an error.
    if(inFile == "")
    {
        usage();
        inputParameters.Status();
        // In file was not specified but it is mandatory.
        std::cerr << "--in is a mandatory argument, "
                  << "but was not specified" << std::endl;
        return(-1);
    }

    // Cannot specify both interleaved & secondOut since secondOut would be N/A.
    if(interleave && !secondOut.IsEmpty())
    {
        usage();
        inputParameters.Status();
        std::cerr << "ERROR: Cannot specify --merge & --secondOut.\n";
        return(-1);
    }

    // Cannot specify both interleaved & secondOut since secondOut would be N/A.
    if(interleave && !secondOut.IsEmpty())
    {
        usage();
        inputParameters.Status();
        std::cerr << "ERROR: Cannot specify --merge & --secondOut.\n";
        return(-1);
    }

    // Cannot specify both splitRG & firstOut/secondOut/unpairedOut
    // since it needs a different file for each RG.
    if(mySplitRG && (!firstOut.IsEmpty() || 
                   !secondOut.IsEmpty() || !unpairedOut.IsEmpty()))
    {
        usage();
        inputParameters.Status();
        std::cerr << "ERROR: Cannot specify --splitRG & --firstOut/--secondOut/--unpairedOut.\n";
        std::cerr << "Use --outBase instead.\n";
        return(-1);
    }
    // Cannot specify splitRG & output to stdout.
    if(mySplitRG && (myOutBase[0] == '-'))
    {
        usage();
        inputParameters.Status();
        std::cerr << "ERROR: Cannot specify --splitRG & write to stdout.\n";
        return(-1);
    }

    // Check to see if the out file was specified, if not, generate it from
    // the input filename.
    if(myOutBase == "")
    {
        // Just remove the extension from the input filename.
        int extStart = inFile.FastFindLastChar('.');
        if(extStart <= 0)
        {
            myOutBase = inFile;
        }
        else
        {
            myOutBase = inFile.Left(extStart);
        }
    }

    if(mySplitRG)
    {
        std::string fqList = myOutBase.c_str();
        fqList += ".list";
        myFqList = ifopen(fqList.c_str(), "w");
        ifprintf(myFqList, "MERGE_NAME\tFASTQ1\tFASTQ2\tRG\n");
    }

    // Check to see if the first/second/single-ended were specified and
    // if not, set them.
    myFirstFileNameExt = "_1.fastq";
    mySecondFileNameExt = "_2.fastq";
    myUnpairedFileNameExt = ".fastq";
    if(interleave)
    {
        myFirstFileNameExt = "_interleaved.fastq";
        myFirstFileNameExt = "_interleaved.fastq";
    }
    getFileName(firstOut, myFirstFileNameExt);
    getFileName(secondOut, mySecondFileNameExt);
    getFileName(unpairedOut, myUnpairedFileNameExt);

    if(params)
    {
        inputParameters.Status();
    }

    // Open the files for reading/writing.
    // Open prior to opening the output files,
    // so if there is an error, the outputs don't get created.
    SamFile samIn;
    samIn.OpenForRead(inFile, &mySamHeader);
    // Skip non-primary reads.
    samIn.SetReadFlags(0, 0x0100);

    // Open the output files if not splitting RG
    if(!mySplitRG)
    {
        myUnpairedFile = ifopen(unpairedOut, "w", myCompression);

        // Only open the first file if it is different than an already opened file.
        if(firstOut != unpairedOut)
        {
            myFirstFile = ifopen(firstOut, "w", myCompression);
        }
        else
        {
            myFirstFile = myUnpairedFile;
        }

        // If it is interleaved or the 2nd file is not a new name, set it appropriately.
        if(interleave || secondOut == firstOut)
        {
            mySecondFile = myFirstFile;
        }
        else if(secondOut == unpairedOut)
        {
            mySecondFile = myUnpairedFile;
        }
        else
        {
            mySecondFile = ifopen(secondOut, "w", myCompression);
        }
    
        if(myUnpairedFile == NULL)
        {
            std::cerr << "Failed to open " << unpairedOut
                      << " so can't convert bam2FastQ.\n";
            return(-1);
        }
        if(myFirstFile == NULL)
        {
            std::cerr << "Failed to open " << firstOut
                      << " so can't convert bam2FastQ.\n";
            return(-1);
        }
        if(mySecondFile == NULL)
        {
            std::cerr << "Failed to open " << secondOut
                      << " so can't convert bam2FastQ.\n";
            return(-1);
        }
    }

    if((readName) || (strcmp(mySamHeader.getSortOrder(), "queryname") == 0))
    {
        readName = true;
    }
    else
    {
        // defaulting to coordinate sorted.
        samIn.setSortedValidation(SamFile::COORDINATE);
    }

    // Setup the '=' translation if the reference was specified.
    if(!refFile.IsEmpty())
    {
        GenomeSequence* refPtr = new GenomeSequence(refFile);
        samIn.SetReadSequenceTranslation(SamRecord::BASES);
        samIn.SetReference(refPtr);
    }

    SamRecord* recordPtr;
    int16_t samFlag;

    SamStatus::Status returnStatus = SamStatus::SUCCESS;
    while(returnStatus == SamStatus::SUCCESS)
    {
        recordPtr = myPool.getRecord();
        if(recordPtr == NULL)
        {
            // Failed to allocate a new record.
            throw(std::runtime_error("Failed to allocate a new SAM/BAM record"));
        }
        if(!samIn.ReadRecord(mySamHeader, *recordPtr))
        {
            // Failed to read a record.
            returnStatus = samIn.GetStatus();
            continue;
        }

        // Have a record.  Check to see if it is a pair or unpaired read.
        samFlag = recordPtr->getFlag();
        if(SamFlag::isPaired(samFlag))
        {
            if(readName)
            {
                handlePairedRN(*recordPtr);
            }
            else
            {
                handlePairedCoord(*recordPtr);
            }
        }
        else
        {
            ++myNumUnpaired;
            writeFastQ(*recordPtr, myUnpairedFile,
                       myUnpairedFileNameExt);
        }
    }

    // Flush All
    cleanUpMateMap(0, true);

    if(returnStatus == SamStatus::NO_MORE_RECS)
    {
        returnStatus = SamStatus::SUCCESS;
    }

    samIn.Close();
    closeFiles();
    
    // Output the results
    std::cerr << "\nFound " << myNumPairs << " read pairs.\n";
    std::cerr << "Found " << myNumUnpaired << " unpaired reads.\n";
    if(myNumMateFailures != 0)
    {
        std::cerr << "Failed to find mates for " << myNumMateFailures
                  << " reads, so they were written as unpaired\n"
                  << "  (not included in either of the above counts).\n";
    }
    if(myNumQualTagErrors != 0)
    {
        std::cerr << myNumQualTagErrors << " records did not have tag "
                  << myQField.c_str() << " or it was invalid, so the quality field was used for those records.\n";
    }

    return(returnStatus);
}
Пример #2
0
int Dedup_LowMem::execute(int argc, char** argv)
{
    /* --------------------------------
     * process the arguments
     * -------------------------------*/
    String inFile, outFile, logFile;
    myDoRecab = false;
    bool removeFlag = false;
    bool verboseFlag = false;
    myForceFlag = false;
    myNumMissingMate = 0;
    myMinQual = DEFAULT_MIN_QUAL;
    String excludeFlags = "0xB04";
    uint16_t intExcludeFlags = 0;
    bool noeof = false;
    bool params = false;

    LongParamContainer parameters;
    parameters.addGroup("Required Parameters");
    parameters.addString("in", &inFile);
    parameters.addString("out", &outFile);
    parameters.addGroup("Optional Parameters");
    parameters.addInt("minQual", & myMinQual);
    parameters.addString("log", &logFile);
    parameters.addBool("oneChrom", &myOneChrom);
    parameters.addBool("recab", &myDoRecab);
    parameters.addBool("rmDups", &removeFlag);
    parameters.addBool("force", &myForceFlag);
    parameters.addString("excludeFlags", &excludeFlags);
    parameters.addBool("verbose", &verboseFlag);
    parameters.addBool("noeof", &noeof);
    parameters.addBool("params", &params);
    parameters.addPhoneHome(VERSION);
    myRecab.addRecabSpecificParameters(parameters);

    ParameterList inputParameters;
    inputParameters.Add(new LongParameters ("Input Parameters",
                                            parameters.getLongParameterList()));

    // parameters start at index 2 rather than 1.
    inputParameters.Read(argc, argv, 2);

    // If no eof block is required for a bgzf file, set the bgzf file type to
    // not look for it.
    if(noeof)
    {
        // Set that the eof block is not required.
        BgzfFileType::setRequireEofBlock(false);
    }

    if(inFile.IsEmpty())
    {
        printUsage(std::cerr);
        inputParameters.Status();
        std::cerr << "Specify an input file" << std::endl;
        return EXIT_FAILURE;
    }

    if(outFile.IsEmpty())
    {
        printUsage(std::cerr);
        inputParameters.Status();
        std::cerr << "Specify an output file" << std::endl;
        return EXIT_FAILURE;
    }

    intExcludeFlags = excludeFlags.AsInteger();

    if(myForceFlag && SamFlag::isDuplicate(intExcludeFlags))
    {
        printUsage(std::cerr);
        inputParameters.Status();
        std::cerr << "Cannot specify --force and Duplicate in the excludeFlags.  Since --force indicates to override"
                  << " previous duplicate setting and the excludeFlags says to skip those, you can't do both.\n";
        return EXIT_FAILURE;
    }

    if(!SamFlag::isSecondary(intExcludeFlags))
    {
        printUsage(std::cerr);
        inputParameters.Status();
        std::cerr << "ERROR: Secondary reads must be excluded, edit --excludeFlags to include 0x0100\n";
        return EXIT_FAILURE;
    }

    if(!(intExcludeFlags & SamFlag::SUPPLEMENTARY_ALIGNMENT))
    {
        printUsage(std::cerr);
        inputParameters.Status();
        std::cerr << "ERROR: Supplementary reads must be excluded, edit --excludeFlags to include 0x0800\n";
        return EXIT_FAILURE;
    }

    if(logFile.IsEmpty())
    {
        logFile = outFile + ".log";
    }

    if(myDoRecab)
    {
        int status = myRecab.processRecabParam();
        if(status != 0)
        {
            inputParameters.Status();
            return(status);
        }
    }

    if(params)
    {
        inputParameters.Status();
    }

    Logger::gLogger = new Logger(logFile.c_str(), verboseFlag);

    /* -------------------------------------------------------------------
     * The arguments are processed.  Prepare the input BAM file,
     * instantiate dedup_LowMem, and construct the read group library map
     * ------------------------------------------------------------------*/

    SamFile samIn;

    samIn.OpenForRead(inFile.c_str());
    // If the file isn't sorted it will throw an exception.
    samIn.setSortedValidation(SamFile::COORDINATE);

    SamFileHeader header;
    samIn.ReadHeader(header);

    buildReadGroupLibraryMap(header);

    lastReference = -1;
    lastCoordinate = -1;

    // for keeping some basic statistics
    uint32_t recordCount = 0;
    uint32_t pairedCount = 0;
    uint32_t properPairCount = 0;
    uint32_t unmappedCount = 0;
    uint32_t reverseCount = 0;
    uint32_t qualCheckFailCount = 0;
    uint32_t secondaryCount = 0;
    uint32_t supplementaryCount = 0;
    uint32_t excludedCount = 0;

    // Now we start reading records
    SamRecord* recordPtr;
    SamStatus::Status returnStatus = SamStatus::SUCCESS;
    while(returnStatus == SamStatus::SUCCESS)
    {
        recordPtr = mySamPool.getRecord();
        if(recordPtr == NULL)
        {
            std::cerr << "Failed to allocate enough records\n";
            return(-1);
        }
        if(!samIn.ReadRecord(header, *recordPtr))
        {
            returnStatus = samIn.GetStatus();
            continue;
        }
        // Take note of properties of this record
        int flag = recordPtr->getFlag();
        if(SamFlag::isPaired(flag))     ++pairedCount;
        if(SamFlag::isProperPair(flag)) ++properPairCount;
        if(SamFlag::isReverse(flag))    ++reverseCount;
        if(SamFlag::isQCFailure(flag))  ++qualCheckFailCount;
        if(SamFlag::isSecondary(flag))  ++secondaryCount;
        if(flag & SamFlag::SUPPLEMENTARY_ALIGNMENT)  ++supplementaryCount;
        if(!SamFlag::isMapped(flag))    ++unmappedCount;

        // put the record in the appropriate maps:
        //   single reads go in myFragmentMap
        //   paired reads go in myPairedMap
        recordCount = samIn.GetCurrentRecordCount();

        // if we have moved to a new position, look back at previous reads for duplicates
        if (hasPositionChanged(*recordPtr))
        {
            cleanupPriorReads(recordPtr);
        }

        // Determine if this read should be checked for duplicates.
        if((!SamFlag::isMapped(flag)) || ((flag & intExcludeFlags) != 0))
        {
            ++excludedCount;

            // No deduping done on this record, but still build the recab table.
            if(myDoRecab)
            {
                myRecab.processReadBuildTable(*recordPtr);
            }
            // Nothing more to do with this record, so
            // release the pointer.
            mySamPool.releaseRecord(recordPtr);
        }
        else
        {
            if(SamFlag::isDuplicate(flag) && !myForceFlag)
            {
                // Error: Marked duplicates, and duplicates aren't excluded.
                Logger::gLogger->error("There are records already duplicate marked.");
                Logger::gLogger->error("Use -f to clear the duplicate flag and start the dedup_LowMem procedure over");
            }

            checkDups(*recordPtr, recordCount);
            mySamPool.releaseRecord(recordPtr);
        }
        // let the user know we're not napping
        if (verboseFlag && (recordCount % 100000 == 0))
        {
            Logger::gLogger->writeLog("recordCount=%u singleKeyMap=%u pairedKeyMap=%u, dictSize=%u",
                                      recordCount, myFragmentMap.size(),
                                      myPairedMap.size(),
                                      myMateMap.size());
        }
    }

    // we're finished reading record so clean up the duplicate search and
    //  close the input file
    cleanupPriorReads(NULL);
    samIn.Close();

    // print some statistics
    Logger::gLogger->writeLog("--------------------------------------------------------------------------");
    Logger::gLogger->writeLog("SUMMARY STATISTICS OF THE READS");
    Logger::gLogger->writeLog("Total number of reads: %u",recordCount);
    Logger::gLogger->writeLog("Total number of paired-end reads: %u",
                              pairedCount);
    Logger::gLogger->writeLog("Total number of properly paired reads: %u",
                              properPairCount);
    Logger::gLogger->writeLog("Total number of unmapped reads: %u",
                              unmappedCount);
    Logger::gLogger->writeLog("Total number of reverse strand mapped reads: %u",
                              reverseCount);
    Logger::gLogger->writeLog("Total number of QC-failed reads: %u",
                              qualCheckFailCount);
    Logger::gLogger->writeLog("Total number of secondary reads: %u",
                              secondaryCount);
    Logger::gLogger->writeLog("Total number of supplementary reads: %u",
                              supplementaryCount);
    Logger::gLogger->writeLog("Size of singleKeyMap (must be zero): %u",
                              myFragmentMap.size());
    Logger::gLogger->writeLog("Size of pairedKeyMap (must be zero): %u",
                              myPairedMap.size());
    Logger::gLogger->writeLog("Total number of missing mates: %u",
                              myNumMissingMate);
    Logger::gLogger->writeLog("Total number of reads excluded from duplicate checking: %u",
                              excludedCount);
    Logger::gLogger->writeLog("--------------------------------------------------------------------------");
    Logger::gLogger->writeLog("Sorting the indices of %d duplicated records",
                              myDupList.size());

    // sort the indices of duplicate records
    std::sort(myDupList.begin(), myDupList.end(),
              std::less<uint32_t> ());

    // get ready to write the output file by making a second pass
    // through the input file
    samIn.OpenForRead(inFile.c_str());
    samIn.ReadHeader(header);

    SamFile samOut;
    samOut.OpenForWrite(outFile.c_str());
    samOut.WriteHeader(header);

    // If we are recalibrating, output the model information.
    if(myDoRecab)
    {
        myRecab.modelFitPrediction(outFile);
    }

    // an iterator to run through the duplicate indices
    int currentDupIndex = 0;
    bool moreDups = !myDupList.empty();

    // let the user know what we're doing
    Logger::gLogger->writeLog("\nWriting %s", outFile.c_str());

    // count the duplicate records as a check
    uint32_t singleDuplicates(0), pairedDuplicates(0);

    // start reading records and writing them out
    SamRecord record;
    while(samIn.ReadRecord(header, record))
    {
        uint32_t currentIndex = samIn.GetCurrentRecordCount();

        bool foundDup = moreDups &&
                        (currentIndex == myDupList[currentDupIndex]);

        // modify the duplicate flag and write out the record,
        // if it's appropriate
        int flag = record.getFlag();
        if (foundDup)
        {
            // this record is a duplicate, so mark it.
            record.setFlag( flag | 0x400 );
            currentDupIndex++;
            // increment duplicate counters to verify we found them all
            if ( ( ( flag & 0x0001 ) == 0 ) || ( flag & 0x0008 ) )
            {   // unpaired or mate unmapped
                singleDuplicates++;
            }
            else
            {
                pairedDuplicates++;
            }
            // recalibrate if necessary.
            if(myDoRecab)
            {
                myRecab.processReadApplyTable(record);
            }

            // write the record if we are not removing duplicates
            if (!removeFlag ) samOut.WriteRecord(header, record);
        }
        else
        {
            if(myForceFlag)
            {
                // this is not a duplicate we've identified but we want to
                // remove any duplicate marking
                record.setFlag( flag & 0xfffffbff ); // unmark duplicate
            }
            // Not a duplicate, so recalibrate if necessary.
            if(myDoRecab)
            {
                myRecab.processReadApplyTable(record);
            }
            samOut.WriteRecord(header, record);
        }

        // Let the user know we're still here
        if (verboseFlag && (currentIndex % 100000 == 0)) {
            Logger::gLogger->writeLog("recordCount=%u", currentIndex);
        }
    }

    // We're done.  Close the files and print triumphant messages.
    samIn.Close();
    samOut.Close();

    Logger::gLogger->writeLog("Successfully %s %u unpaired and %u paired duplicate reads",
                              removeFlag ? "removed" : "marked" ,
                              singleDuplicates,
                              pairedDuplicates/2);
    Logger::gLogger->writeLog("\nDedup_LowMem complete!");
    return 0;
}
Пример #3
0
void testIndex(BamIndex& bamIndex)
{
    assert(bamIndex.getNumMappedReads(1) == 2);
    assert(bamIndex.getNumUnMappedReads(1) == 0);
    assert(bamIndex.getNumMappedReads(0) == 4);
    assert(bamIndex.getNumUnMappedReads(0) == 1);
    assert(bamIndex.getNumMappedReads(23) == -1);
    assert(bamIndex.getNumUnMappedReads(23) == -1);
    assert(bamIndex.getNumMappedReads(-1) == 0);
    assert(bamIndex.getNumUnMappedReads(-1) == 2);
    assert(bamIndex.getNumMappedReads(-2) == -1);
    assert(bamIndex.getNumUnMappedReads(-2) == -1);
    assert(bamIndex.getNumMappedReads(22) == 0);
    assert(bamIndex.getNumUnMappedReads(22) == 0);

    // Get the chunks for reference id 1.
    Chunk testChunk;
    SortedChunkList chunkList;
    assert(bamIndex.getChunksForRegion(1, -1, -1, chunkList) == true);
    assert(!chunkList.empty());
    testChunk = chunkList.pop();
    assert(chunkList.empty());
    assert(testChunk.chunk_beg == 0x4e7);
    assert(testChunk.chunk_end == 0x599);

    // Get the chunks for reference id 0.
    assert(bamIndex.getChunksForRegion(0, -1, -1, chunkList) == true);
    assert(!chunkList.empty());
    testChunk = chunkList.pop();
    assert(chunkList.empty());
    assert(testChunk.chunk_beg == 0x360);
    assert(testChunk.chunk_end == 0x4e7);


    // Get the chunks for reference id 2.
    assert(bamIndex.getChunksForRegion(2, -1, -1, chunkList) == true);
    assert(!chunkList.empty());
    testChunk = chunkList.pop();
    assert(chunkList.empty());
    assert(testChunk.chunk_beg == 0x599);
    assert(testChunk.chunk_end == 0x5ea);

    // Get the chunks for reference id 3.
    // There isn't one for this ref id, but still successfully read the file,
    // so it should return true, but the list should be empty.
    assert(bamIndex.getChunksForRegion(3, -1, -1, chunkList) == true);
    assert(chunkList.empty());

    // Test reading an indexed bam file.
    SamFile inFile;
    assert(inFile.OpenForRead("testFiles/sortedBam.bam"));
    inFile.setSortedValidation(SamFile::COORDINATE);
    assert(inFile.ReadBamIndex("testFiles/sortedBam.bam.bai"));
    SamFileHeader samHeader;
    assert(inFile.ReadHeader(samHeader));
    SamRecord samRecord;

    // Test getting num mapped/unmapped reads.
    assert(inFile.getNumMappedReadsFromIndex(1) == 2);
    assert(inFile.getNumUnMappedReadsFromIndex(1) == 0);
    assert(inFile.getNumMappedReadsFromIndex(0) == 4);
    assert(inFile.getNumUnMappedReadsFromIndex(0) == 1);
    assert(inFile.getNumMappedReadsFromIndex(23) == -1);
    assert(inFile.getNumUnMappedReadsFromIndex(23) == -1);
    assert(inFile.getNumMappedReadsFromIndex(-1) == 0);
    assert(inFile.getNumUnMappedReadsFromIndex(-1) == 2);
    assert(inFile.getNumMappedReadsFromIndex(-2) == -1);
    assert(inFile.getNumUnMappedReadsFromIndex(-2) == -1);
    assert(inFile.getNumMappedReadsFromIndex(22) == 0);
    assert(inFile.getNumUnMappedReadsFromIndex(22) == 0);

    assert(inFile.getNumMappedReadsFromIndex("2", samHeader) == 2);
    assert(inFile.getNumUnMappedReadsFromIndex("2", samHeader) == 0);
    assert(inFile.getNumMappedReadsFromIndex("1", samHeader) == 4);
    assert(inFile.getNumUnMappedReadsFromIndex("1", samHeader) == 1);
    assert(inFile.getNumMappedReadsFromIndex("22", samHeader) == 0);
    assert(inFile.getNumUnMappedReadsFromIndex("22", samHeader) == 0);
    assert(inFile.getNumMappedReadsFromIndex("", samHeader) == 0);
    assert(inFile.getNumUnMappedReadsFromIndex("*", samHeader) == 2);
    assert(inFile.getNumMappedReadsFromIndex("unknown", samHeader) == -1);
    assert(inFile.getNumUnMappedReadsFromIndex("unknown", samHeader) == -1);
    assert(inFile.getNumMappedReadsFromIndex("X", samHeader) == 0);
    assert(inFile.getNumUnMappedReadsFromIndex("X", samHeader) == 0);

    // Section -1 = Ref *: 2 records (8 & 10 from testSam.sam that is reflected
    // in the validation.
    assert(inFile.SetReadSection(-1));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead8(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead10(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);

    // Section 2 = Ref 3: 1 records (9 from testSam.sam that is reflected
    // in the validation.
    assert(inFile.SetReadSection(2));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead9(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);

    // Section 0 = Ref 1: 5 records (3, 4, 1, 2, & 6 from testSam.sam that is
    // reflected in the validation.
    assert(inFile.SetReadSection(0));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead3(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead4(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead1(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead2(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead6(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);

    // Section 1 = Ref 2: 2 records (5 & 7 from testSam.sam that is reflected
    // in the validation.
    assert(inFile.SetReadSection(1));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead5(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead7(samRecord);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);

    // Section 3 to 22 (ref 4 - 23): 0 records.
    for(int i = 3; i < 23; i++)
    {
        assert(inFile.SetReadSection(i));
        assert(inFile.ReadRecord(samHeader, samRecord) == false);
    }


    // Set the read section.
    assert(inFile.SetReadSection("1", 1010, 1012));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead1(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 2);
    assert(samRecord.getNumOverlaps(1010, 1012) == 2);
    assert(samRecord.getNumOverlaps(1010, 1020) == 5);
    assert(samRecord.getNumOverlaps(1010, 1011) == 1);
    assert(samRecord.getNumOverlaps(1011, 1012) == 1);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead2(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 0);
    assert(samRecord.getNumOverlaps(1010, 1012) == 0);
    assert(samRecord.getNumOverlaps(1010, 1020) == 0);
    assert(samRecord.getNumOverlaps(1010, 1011) == 0);
    assert(samRecord.getNumOverlaps(1011, 1012) == 0);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);
           
    assert(inFile.SetReadSection("1", 1010, 1020));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead1(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 5);
    assert(samRecord.getNumOverlaps(1010, 1012) == 2);
    assert(samRecord.getNumOverlaps(1010, 1020) == 5);
    assert(samRecord.getNumOverlaps(1010, 1011) == 1);
    assert(samRecord.getNumOverlaps(1011, 1012) == 1);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead2(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 0);
    assert(samRecord.getNumOverlaps(1010, 1012) == 0);
    assert(samRecord.getNumOverlaps(1010, 1020) == 0);
    assert(samRecord.getNumOverlaps(1010, 1011) == 0);
    assert(samRecord.getNumOverlaps(1011, 1012) == 0);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);
           
    assert(inFile.SetReadSection("1", 1010, 1011));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead1(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 1);
    assert(samRecord.getNumOverlaps(1010, 1012) == 2);
    assert(samRecord.getNumOverlaps(1010, 1020) == 5);
    assert(samRecord.getNumOverlaps(1010, 1011) == 1);
    assert(samRecord.getNumOverlaps(1011, 1012) == 1);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);
           
    assert(inFile.SetReadSection("1", 1011, 1012));
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead1(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 1);
    assert(samRecord.getNumOverlaps(1010, 1012) == 2);
    assert(samRecord.getNumOverlaps(1010, 1020) == 5);
    assert(samRecord.getNumOverlaps(1010, 1011) == 1);
    assert(samRecord.getNumOverlaps(1011, 1012) == 1);
    assert(inFile.ReadRecord(samHeader, samRecord));
    validateRead2(samRecord);
    assert(inFile.GetNumOverlaps(samRecord) == 0);
    assert(samRecord.getNumOverlaps(1010, 1012) == 0);
    assert(samRecord.getNumOverlaps(1010, 1020) == 0);
    assert(samRecord.getNumOverlaps(1010, 1011) == 0);
    assert(samRecord.getNumOverlaps(1011, 1012) == 0);
    assert(inFile.ReadRecord(samHeader, samRecord) == false);
           
}