Returns dictionary of cluster IDs:seq IDs

    Overall function for de novo clustering with usearch61

    seq_path:  fasta filepath to be clustered with usearch61
    percent_id:  percentage id to cluster at
    rev: enable reverse strand matching for clustering
    save_intermediate_files: Saves intermediate files created during clustering
    minlen: minimum sequence length
    output_dir: directory to output log, OTU mapping, and intermediate files
    remove_usearch_logs: Saves usearch log files
    verbose: print current processing step to stdout
    wordlength: word length to use for clustering
    usearch_fast_cluster: Use usearch61 fast cluster option, not as memory
     efficient as the default cluster_smallmem option, requires sorting by
     length, and does not allow reverse strand matching.
    usearch61_sort_method:  Sort sequences by abundance or length by using
     functionality provided by usearch61, or do not sort by using None option.
    otu_prefix: label to place in front of OTU IDs, used to prevent duplicate
     IDs from appearing with reference based OTU picking.
    usearch61_maxrejects: Number of rejects allowed by usearch61
    usearch61_maxaccepts: Number of accepts allowed by usearch61
    sizeorder: used for clustering based upon abundance of seeds
    threads: Specify number of threads used per core per CPU
    HALT_EXEC: application controller option to halt execution.

def usearch61_denovo_cluster(seq_path,
                             percent_id=0.97,
                             rev=False,
                             save_intermediate_files=True,
                             minlen=64,
                             output_dir='.',
                             remove_usearch_logs=False,
                             verbose=False,
                             wordlength=8,
                             usearch_fast_cluster=False,
                             usearch61_sort_method='abundance',
                             otu_prefix="denovo",
                             usearch61_maxrejects=32,
                             usearch61_maxaccepts=1,
                             sizeorder=False,
                             threads=1.0,
                             HALT_EXEC=False,
                             file_prefix="denovo_"
                             ):
    """ Returns dictionary of cluster IDs:seq IDs

    Overall function for de novo clustering with usearch61

    seq_path:  fasta filepath to be clustered with usearch61
    percent_id:  percentage id to cluster at
    rev: enable reverse strand matching for clustering
    save_intermediate_files: Saves intermediate files created during clustering
    minlen: minimum sequence length
    output_dir: directory to output log, OTU mapping, and intermediate files
    remove_usearch_logs: Saves usearch log files
    verbose: print current processing step to stdout
    wordlength: word length to use for clustering
    usearch_fast_cluster: Use usearch61 fast cluster option, not as memory
     efficient as the default cluster_smallmem option, requires sorting by
     length, and does not allow reverse strand matching.
    usearch61_sort_method:  Sort sequences by abundance or length by using
     functionality provided by usearch61, or do not sort by using None option.
    otu_prefix: label to place in front of OTU IDs, used to prevent duplicate
     IDs from appearing with reference based OTU picking.
    usearch61_maxrejects: Number of rejects allowed by usearch61
    usearch61_maxaccepts: Number of accepts allowed by usearch61
    sizeorder: used for clustering based upon abundance of seeds
    threads: Specify number of threads used per core per CPU
    HALT_EXEC: application controller option to halt execution.
    """

    files_to_remove = []

    # Need absolute paths to avoid potential problems with app controller
    if output_dir:
        output_dir = abspath(output_dir) + '/'
    seq_path = abspath(seq_path)

    try:
        if verbose and usearch61_sort_method is not None and\
                not usearch_fast_cluster:
            print "Sorting sequences according to %s..." % usearch61_sort_method

        # fast sorting option automatically performs length sorting
        if usearch61_sort_method == 'abundance' and not usearch_fast_cluster:
            intermediate_fasta, dereplicated_uc, app_result =\
                sort_by_abundance_usearch61(seq_path, output_dir, rev,
                                            minlen, remove_usearch_logs, HALT_EXEC,
                                            output_fna_filepath=join(
                                                output_dir,
                                                file_prefix + 'abundance_sorted.fna'),
                                            output_uc_filepath=join(output_dir,
                                                                    file_prefix + 'abundance_sorted.uc'), threads=threads)
            if not save_intermediate_files:
                files_to_remove.append(intermediate_fasta)
                files_to_remove.append(dereplicated_uc)
        elif usearch61_sort_method == 'length' and not usearch_fast_cluster:
            intermediate_fasta, app_result =\
                sort_by_length_usearch61(seq_path, output_dir, minlen,
                                         remove_usearch_logs, HALT_EXEC,
                                         output_fna_filepath=join(output_dir,
                                                                  file_prefix + 'length_sorted.fna'))
            if not save_intermediate_files:
                files_to_remove.append(intermediate_fasta)
        else:
            intermediate_fasta = seq_path

        if verbose:
            print "Clustering sequences de novo..."

        if usearch_fast_cluster:
            clusters_fp, app_result = usearch61_fast_cluster(
                intermediate_fasta,
                percent_id, minlen, output_dir, remove_usearch_logs, wordlength,
                usearch61_maxrejects, usearch61_maxaccepts, HALT_EXEC,
                output_uc_filepath=join(
                    output_dir,
                    file_prefix + 'fast_clustered.uc'), threads=threads)
            if not save_intermediate_files:
                files_to_remove.append(clusters_fp)
        else:
            clusters_fp, app_result =\
                usearch61_smallmem_cluster(intermediate_fasta, percent_id,
                                           minlen, rev, output_dir, remove_usearch_logs, wordlength,
                                           usearch61_maxrejects, usearch61_maxaccepts, sizeorder, HALT_EXEC,
                                           output_uc_filepath=join(output_dir,
                                                                   file_prefix + 'smallmem_clustered.uc'))
            if not save_intermediate_files:
                files_to_remove.append(clusters_fp)

    except ApplicationError:
        raise ApplicationError('Error running usearch61. Possible causes are '
                               'unsupported version (current supported version is usearch ' +
                               'v6.1.544) is installed or improperly formatted input file was ' +
                               'provided')

    except ApplicationNotFoundError:
        remove_files(files_to_remove)
        raise ApplicationNotFoundError('usearch61 not found, is it properly ' +
                                       'installed?')

    if usearch61_sort_method == 'abundance' and not usearch_fast_cluster:
        de_novo_clusters, failures =\
            parse_usearch61_clusters(open(clusters_fp, "U"), otu_prefix)
        dereplicated_clusters =\
            parse_dereplicated_uc(open(dereplicated_uc, "U"))
        clusters = merge_clusters_dereplicated_seqs(de_novo_clusters,
                                                    dereplicated_clusters)

    else:
        clusters, failures =\
            parse_usearch61_clusters(open(clusters_fp, "U"), otu_prefix)

    if not save_intermediate_files:
        remove_files(files_to_remove)

    return clusters