<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def launch_workflow(seqs_fp, working_dir, mean_error, error_dist, indel_prob, indel_max, trim_length, left_trim_length, min_size, ref_fp, ref_db_fp, threads_per_sample=1, sim_thresh=None, coverage_thresh=None):
 """Launch full deblur workflow for a single post split-libraries fasta file Parameters seqs_fp: string a post split library fasta file for debluring working_dir: string working directory path mean_error: float mean error for original sequence estimate error_dist: list list of error probabilities for each hamming distance indel_prob: float insertion/deletion (indel) probability indel_max: integer maximal indel number trim_length: integer sequence trim length left_trim_length: integer trim the first n reads min_size: integer upper limit on sequence abundance (discard sequences below limit) ref_fp: tuple filepath(s) to FASTA reference database for artifact removal ref_db_fp: tuple filepath(s) to SortMeRNA indexed database for artifact removal threads_per_sample: integer, optional number of threads to use for SortMeRNA/mafft/vsearch (0 for max available) sim_thresh: float, optional the minimal similarity for a sequence to the database. if None, take the defaults (0.65 for negate=False, 0.95 for negate=True) coverage_thresh: float, optional the minimal coverage for alignment of a sequence to the database. if None, take the defaults (0.3 for negate=False, 0.95 for negate=True) Return ------ output_no_chimers_fp : string filepath to fasta file with no chimeras of None if error encountered """

    logger = logging.getLogger(__name__)
    logger.info('--------------------------------------------------------')
    logger.info('launch_workflow for file %s' % seqs_fp)

    # Step 1: Trim sequences to specified length
    output_trim_fp = join(working_dir, "%s.trim" % basename(seqs_fp))
    with open(output_trim_fp, 'w') as out_f:
        for label, seq in trim_seqs(
                input_seqs=sequence_generator(seqs_fp),
                trim_len=trim_length,
                left_trim_len=left_trim_length):
            out_f.write(">%s\n%s\n" % (label, seq))
    # Step 2: Dereplicate sequences
    output_derep_fp = join(working_dir,
                           "%s.derep" % basename(output_trim_fp))
    dereplicate_seqs(seqs_fp=output_trim_fp,
                     output_fp=output_derep_fp,
                     min_size=min_size, threads=threads_per_sample)
    # Step 3: Remove artifacts
    output_artif_fp, num_seqs_left, _ = remove_artifacts_seqs(seqs_fp=output_derep_fp,
                                                              ref_fp=ref_fp,
                                                              working_dir=working_dir,
                                                              ref_db_fp=ref_db_fp,
                                                              negate=True,
                                                              threads=threads_per_sample,
                                                              sim_thresh=sim_thresh)
    if not output_artif_fp:
        warnings.warn('Problem removing artifacts from file %s' %
                      seqs_fp, UserWarning)
        logger.warning('remove artifacts failed, aborting')
        return None
    # Step 4: Multiple sequence alignment
    if num_seqs_left > 1:
        output_msa_fp = join(working_dir,
                             "%s.msa" % basename(output_artif_fp))
        alignment = multiple_sequence_alignment(seqs_fp=output_artif_fp,
                                                threads=threads_per_sample)
        if not alignment:
            warnings.warn('Problem performing multiple sequence alignment '
                          'on file %s' % seqs_fp, UserWarning)
            logger.warning('msa failed. aborting')
            return None
    elif num_seqs_left == 1:
        # only one sequence after remove artifacts (but could be many reads)
        # no need to run MSA - just use the pre-msa file as input for next step
        output_msa_fp = output_artif_fp
    else:
        err_msg = ('No sequences left after artifact removal in '
                   'file %s' % seqs_fp)
        warnings.warn(err_msg, UserWarning)
        logger.warning(err_msg)
        return None
    # Step 5: Launch deblur
    output_deblur_fp = join(working_dir,
                            "%s.deblur" % basename(output_msa_fp))
    with open(output_deblur_fp, 'w') as f:
        seqs = deblur(sequence_generator(output_msa_fp), mean_error,
                      error_dist, indel_prob, indel_max)
        if seqs is None:
            warnings.warn('multiple sequence alignment file %s contains '
                          'no sequences' % output_msa_fp, UserWarning)
            logger.warn('no sequences returned from deblur for file %s' %
                        output_msa_fp)
            return None
        for s in seqs:
            # remove '-' from aligned sequences
            s.sequence = s.sequence.replace('-', '')
            f.write(s.to_fasta())
    # Step 6: Chimera removal
    output_no_chimeras_fp = remove_chimeras_denovo_from_seqs(
        output_deblur_fp, working_dir, threads=threads_per_sample)
    logger.info('finished processing file')
    return output_no_chimeras_fp