This function will take a preprocessed seqFN and offsetFN file and create the MSBWT from them, it 
    is the main function to call from MSBWTGen when attempting to build a BWT
    @param seqFNPrefix - the preprocessed seqFN file(s) prefix, '.npy' format of uint8s
    @param offsetFN - the offsets into seqFN indicating the start of a string
    @param mergedFN - the final destination output, '.npy' file
    @param numProcs - the maximum number of processes to use

def createFromSeqs(seqFNPrefix, offsetFN, mergedFN, numProcs, areUniform, logger):
    '''
    This function will take a preprocessed seqFN and offsetFN file and create the MSBWT from them, it 
    is the main function to call from MSBWTGen when attempting to build a BWT
    @param seqFNPrefix - the preprocessed seqFN file(s) prefix, '.npy' format of uint8s
    @param offsetFN - the offsets into seqFN indicating the start of a string
    @param mergedFN - the final destination output, '.npy' file
    @param numProcs - the maximum number of processes to use
    '''
    totalStartTime = time.time()
    numValidChars = 6
    
    #clear anything that may already have been associated with it
    clearAuxiliaryData(mergedFN)
    
    #start with column 2 for the iterations, (this is really l(s)-2 where s is a string to merge)
    startingColumn = 2
    
    #memmap the two string data files
    offsetData = np.load(offsetFN, 'r')
    if areUniform:
        uniformLength = int(offsetData[0])
        firstSeq = np.load(seqFNPrefix+'.0.npy', 'r')
        numSeqs = firstSeq.shape[0]
    else:
        numSeqs = offsetData.shape[0]-1
    
    logger.info('Preparing to merge '+str(numSeqs)+' sequences...')
    
    #depth should always be greater than or equal to 1
    depth = max(int(math.ceil(math.log(numProcs, numValidChars-1)))+1, int(math.ceil(math.log(numSeqs/1000000.0, numValidChars))), 1)
    
    logger.info('Setting depth to '+str(depth)+'...')        
    
    #initialize the total information
    if areUniform:
        totalSize = uniformLength*numSeqs
    else:
        totalSize = offsetData[-1]
    bwt = np.lib.format.open_memmap(mergedFN, 'w+', '<u1', (totalSize,))
    
    #initialize the count information
    fmStarts = {}
    allBwtCounts = [0]*numValidChars
    allFirstCounts = [0]*numValidChars
    cOffset = {}
    totalCounts = {}
    
    #prepare to make the first inserts
    logger.info('Generating level 1 insertions...')
    st = time.time()
    
    tups = []
    segLen = numSeqs / numProcs
    for i in xrange(0, numProcs-1):
        tup = (offsetFN, seqFNPrefix, mergedFN, depth, numValidChars, i*segLen, (i+1)*segLen, areUniform)
        tups.append(tup)
    
    tup = (offsetFN, seqFNPrefix, mergedFN, depth, numValidChars, segLen*(numProcs-1), numSeqs, areUniform)
    tups.append(tup)
    
    if numProcs > 1:
        #create a pool of processes based on the input
        myPool = multiprocessing.Pool(numProcs)
        initRets = myPool.imap(bwtInitialInsertionsPoolCall, tups)
    else:
        initRets = []
        for tup in tups:
            initRets.append(bwtInitialInsertionsPoolCall(tup))
    
    #create our initial information based on the return
    fmDeltas = {}
    insertFNs = {}
    for initRet in initRets:
        (retFmDeltas, retInsertFNs) = initRet
        for key in retFmDeltas.keys():
            if not fmDeltas.has_key(key):
                fmDeltas[key] = [0]*numValidChars
                np.lib.format.open_memmap(mergedFN+'.'+key+'.'+str(startingColumn-1)+'.npy', 'w+', '<u8,<u1,<u4', (0,))
            fmDeltas[key] = np.add(fmDeltas[key], retFmDeltas[key])
            
            if not insertFNs.has_key(key):
                insertFNs[key] = []
            insertFNs[key] += retInsertFNs[key]    
    
    if numProcs > 1:
        myPool.terminate()
        myPool.join()
        myPool = None
    
    for key in fmDeltas.keys():
        fmStarts[key] = [0]*numValidChars
        cOffset[key] = 0
        totalCounts[key] = 0
    
    et = time.time()
    
    #prepare to do deeper iterations
    i = 0
    
    #dummy, just for entering first loop
    logger.info('Finished init in '+str(et-st)+' seconds.')
    logger.info('Beginning iterations...')
    
    totalCounts = {}
    
    iterateCreateFromSeqs(startingColumn, fmStarts, fmDeltas, allFirstCounts, allBwtCounts, cOffset, totalCounts, numValidChars,
                          mergedFN, seqFNPrefix, offsetFN, insertFNs, numProcs, areUniform, depth, logger)
    
    totalEndTime = time.time()
    logger.info('Final output saved to \''+mergedFN+'\'.')
    logger.info('Finished all iterations in '+str(totalEndTime-totalStartTime)+' seconds.')

#TODO: This is complicated to figure out initial state, review the entire process with redocumentation so you can 
#implement this correctly, MAKE SURE ITS TESTED
#def continueCreateFromSeqs(seqFNPrefix, offsetFN, mergedFN, numProcs, areUniform, logger):
    '''
    This function will take a preprocessed seqFN and offsetFN file and continue the creation of the MSBWT from them
    @param seqFNPrefix - the preprocessed seqFN file(s) prefix, '.npy' format of uint8s
    @param offsetFN - the offsets into seqFN indicating the start of a string
    @param mergedFN - the final destination output, '.npy' file
    @param numProcs - the maximum number of processes to use
    '''