This function iterates through the BWT and counts the letters as it goes to create the FM index.  For example, the string 'ACC$' would have BWT
        'C$CA'.  The FM index would iterate over this and count the occurence of the letter it found so you'd end up with this:
        BWT    FM-index
        C    0    0    0
        $    0    0    1
        C    1    0    1
        A    1    0    2
             1    1    2
        This is necessary for finding the occurrence of a letter using the getOccurrenceOfCharAtIndex(...) function.
        In reality, this function creates a sampled FM-index more complicated than the uncompressed counter-part.  This is 
        because the 2048 size bins don't fall evenly all the time.  A second data structure is used to tell you where to start
        a particular FM-index count.  The two files necessary are '<DIR>/comp_fmIndex.npy' and '<DIR>/comp_refIndex.npy'

def constructFMIndex(self, logger):
        '''
        This function iterates through the BWT and counts the letters as it goes to create the FM index.  For example, the string 'ACC$' would have BWT
        'C$CA'.  The FM index would iterate over this and count the occurence of the letter it found so you'd end up with this:
        BWT    FM-index
        C    0    0    0
        $    0    0    1
        C    1    0    1
        A    1    0    2
             1    1    2
        This is necessary for finding the occurrence of a letter using the getOccurrenceOfCharAtIndex(...) function.
        In reality, this function creates a sampled FM-index more complicated than the uncompressed counter-part.  This is 
        because the 2048 size bins don't fall evenly all the time.  A second data structure is used to tell you where to start
        a particular FM-index count.  The two files necessary are '<DIR>/comp_fmIndex.npy' and '<DIR>/comp_refIndex.npy'
        '''
        #sampling method
        self.searchCache = {}
        self.bitPower = 11
        self.binSize = 2**self.bitPower
        
        self.fmIndexFN = self.dirName+'/comp_fmIndex.npy'
        self.fmRefFN = self.dirName+'/comp_refIndex.npy'
        
        if os.path.exists(self.fmIndexFN) and os.path.exists(self.fmRefFN):
            #both exist, just memmap them
            self.partialFM = np.load(self.fmIndexFN, 'r')
            self.refFM = np.load(self.fmRefFN, 'r')
        else:
            if logger != None:
                logger.info('First time calculation of \'%s\'' % self.fmIndexFN)
            
            #pre-allocate space
            samplingSize = int(math.ceil(float(self.totalSize)/self.binSize))
            self.partialFM = np.lib.format.open_memmap(self.fmIndexFN, 'w+', '<u8', (samplingSize, self.vcLen))
            self.refFM = np.lib.format.open_memmap(self.fmRefFN, 'w+', '<u8', (samplingSize,))
            
            countsSoFar = np.cumsum(self.totalCounts)-self.totalCounts
            totalCounts = 0
            
            prevStart = 0
            bwtIndex = 0
            chunkSize = 10000
            
            samplingID = 0
            
            #iterate through the whole file creating dynamically sized bins
            while bwtIndex < self.bwt.shape[0] and samplingID < samplingSize:
                #extract letters and counts so we can do sums
                letters = np.bitwise_and(self.bwt[bwtIndex:bwtIndex+chunkSize], self.mask)
                counts = np.right_shift(self.bwt[bwtIndex:bwtIndex+chunkSize], self.letterBits, dtype='<u8')
                
                #numpy methods for find the powers
                i = 1
                same = (letters[0:-1] == letters[1:])
                while np.count_nonzero(same) > 0:
                    (counts[i:])[same] *= self.numPower
                    i += 1
                    same = np.bitwise_and(same[0:-1], same[1:])
                
                offsets = np.cumsum(counts)
                
                #this is basically looking for a clean breakpoint for our bin to end
                moreToUpdate = True
                while moreToUpdate:
                    prevStart = np.searchsorted(offsets, samplingID*self.binSize-totalCounts, 'right')
                    if prevStart == letters.shape[0]:
                        prevStart -= 1
                        while prevStart > 0 and letters[prevStart] == letters[prevStart-1]:
                            prevStart -= 1
                        moreToUpdate = False
                    else:
                        while prevStart > 0 and letters[prevStart] == letters[prevStart-1]:
                            prevStart -= 1
                        
                        self.refFM[samplingID] = bwtIndex+prevStart
                        if prevStart > 0:
                            self.partialFM[samplingID][:] = np.add(countsSoFar, np.bincount(letters[0:prevStart], counts[0:prevStart], self.vcLen))
                        else:
                            self.partialFM[samplingID][:] = countsSoFar
                        samplingID += 1
                        
                        
                bwtIndex += prevStart
                if prevStart > 0:
                    countsSoFar += np.bincount(letters[0:prevStart], counts[0:prevStart], self.vcLen)
                    totalCounts += np.sum(np.bincount(letters[0:prevStart], counts[0:prevStart], self.vcLen))
            
        #we'll use this later when we do lookups
        self.offsetSum = np.sum(self.partialFM[0])