docs: 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])