tmap_map_sams_t * tmap_map2_aux_core(tmap_map_opt_t *_opt, tmap_seq_t *seqs[4], tmap_refseq_t *refseq, tmap_bwt_t *bwt, tmap_sa_t *sa, tmap_bwt_match_hash_t *hash, tmap_rand_t *rand, tmap_map2_global_mempool_t *pool) { tmap_map_opt_t opt; tmap_seq_t *orig_seq = NULL; tmap_string_t *seq[2]={NULL, NULL}; tmap_string_t *rseq[2]={NULL, NULL}; tmap_map_sams_t *sams = NULL; tmap_map2_aln_t *b[2]={NULL,NULL}; tmap_string_t *bases = NULL; int32_t i, k, l, num_n; opt = (*_opt); // sequence length bases = tmap_seq_get_bases(seqs[0]); l = bases->l; // update the local opt tmap_map2_aux_core_update_opt(&opt, _opt, l); // set opt->score_thr if(pool->max_l < l) { // then enlarge working space for tmap_sw_extend_core() int32_t tmp; if(0 == opt.pen_gape) { tmp = ((l + 1) / 2 * opt.score_match + opt.pen_gape) + l; } else { tmp = ((l + 1) / 2 * opt.score_match + opt.pen_gape) / opt.pen_gape + l; } pool->max_l = l; pool->aln_mem = tmap_realloc(pool->aln_mem, sizeof(uint8_t) * (tmp + 2) * 24, "pool->aln_mem"); } // get the number of Ns for(i=num_n=0;i<l;i++) { uint8_t c = (uint8_t)tmap_nt_char_to_int[(int)bases->s[i]]; if(c >= 4) num_n++; // FIXME: ambiguous bases are not properly handled } // will we always be lower than the score threshold if((l*opt.score_match) + (num_n*opt.pen_mm) < opt.score_thr) { return tmap_map_sams_init(NULL); } // save sequences seq[0] = tmap_seq_get_bases(seqs[0]); seq[1] = tmap_seq_get_bases(seqs[1]); rseq[0] = tmap_seq_get_bases(seqs[2]); rseq[1] = tmap_seq_get_bases(seqs[3]); // handle ambiguous bases if(0 < num_n) { // save original to de-randomize later orig_seq = tmap_seq_clone(seqs[0]); // randomize for(i=0;i<l;i++) { uint8_t c = (uint8_t)bases->s[i]; if(c >= 4) { c = (int)(tmap_rand_get(rand) * 4); // FIXME: ambiguous bases are not properly handled seq[0]->s[i] = c; // original seq[1]->s[l-1-i] = 3 - c; // reverse compliment rseq[0]->s[l-1-i] = 3 - c; // reverse compliment rseq[1]->s[i] = c; // original //rseq[0]->s[l-1-i] = c; // reverse //rseq[1]->s[i] = 3 - c; // compliment } } } // alignment b[0] = tmap_map2_aux_aln(&opt, refseq, bwt, sa, hash, seq, 0, pool); for(k = 0; k < b[0]->n; ++k) { if(b[0]->hits[k].n_seeds < opt.seeds_rev) break; } if(k < b[0]->n) { b[1] = tmap_map2_aux_aln(&opt, refseq, bwt, sa, hash, rseq, 1, pool); for(i = 0; i < b[1]->n; ++i) { tmap_map2_hit_t *p = b[1]->hits + i; int x = p->beg; p->flag ^= 0x10, p->is_rev ^= 1; // flip the strand p->beg = l - p->end; p->end = l - x; if(p->l == 0) { if(refseq->len * 2 < (p->k + p->tlen)) p->k = 0; else p->k = 2 * refseq->len - (p->k + p->tlen); } } tmap_map2_aux_merge_hits(b, l, 0); } else b[1] = 0; // set the flag to forward/reverse tmap_map2_aux_flag_fr(b); // tlen may overestimated due to not counting insertions properly, bound it! for(i = 0; i < b[0]->n; ++i) { if(refseq->len * 2 <= b[0]->hits[i].k + b[0]->hits[i].tlen) { b[0]->hits[i].tlen = (refseq->len * 2) - b[0]->hits[i].k; } else if(b[0]->hits[i].k < refseq->len && refseq->len <= b[0]->hits[i].k + b[0]->hits[i].tlen) { b[0]->hits[i].tlen = refseq->len - b[0]->hits[i].k; } } // make one-based for pac2real for(i = 0; i < b[0]->n; ++i) { b[0]->hits[i].k++; } // store in SAM sams = tmap_map2_aux_store_hits(refseq, &opt, b[0], l); // free tmap_map2_aln_destroy(b[0]); // revert ambiguous bases if(0 < num_n) { // de-randomize bases = tmap_seq_get_bases(orig_seq); for(i=0;i<l;i++) { uint8_t c = (uint8_t)bases->s[i]; if(c >= 4) { // NB: always keep them at "4" seq[0]->s[i] = c; // original seq[1]->s[l-1-i] = c; // reverse compliment rseq[0]->s[l-1-i] = c; // reverse compliment rseq[1]->s[i] = c; // original //rseq[0]->s[l-1-i] = c; // reverse //rseq[1]->s[i] = 3 - c; // compliment } } tmap_seq_destroy(orig_seq); } return sams; }
tmap_map_sams_t * tmap_map1_aux_core(tmap_seq_t *seq, tmap_index_t *index, tmap_bwt_match_hash_t *hash, tmap_bwt_match_width_t *width, tmap_bwt_match_width_t *seed_width, tmap_map_opt_t *opt, tmap_map1_aux_stack_t *stack, int32_t seed2_len) { int32_t max_mm = opt->max_mm, max_gapo = opt->max_gapo, max_gape = opt->max_gape, seed_max_diff = opt->seed_max_diff; int32_t best_score, next_best_score; int32_t best_cnt = 0; int32_t i, j, num_n = 0; int32_t max_edit_score; tmap_bwt_match_occ_t match_sa_start; tmap_string_t *bases=NULL; tmap_map_sams_t *sams = NULL; int32_t max_diff, best_diff; tmap_bwt_int_t k, l; tmap_refseq_t *refseq = index->refseq; tmap_bwt_t *bwt = index->bwt; tmap_sa_t *sa = index->sa; tmap_map1_aux_occ_t *occs = NULL; max_edit_score = opt->pen_mm; //if(max_edit_score < opt->pen_gapo + opt->pen_gape) max_edit_score = opt->pen_gapo + opt->pen_gape; //if(max_edit_score < opt->pen_gape) max_edit_score = opt->pen_gape; bases = tmap_seq_get_bases(seq); /* fputc('\n', stderr); for(i=0;i<bases->l;i++) { fputc("ACGTN"[(int)bases->s[i]], stderr); } fputc('\n', stderr); */ // the maximum # of differences if(bases->l <= TMAP_MAP_OPT_MAX_DIFF_READ_LENGTH) { best_diff = max_diff = opt->max_diff_table[bases->l]; } else { best_diff = max_diff = opt->max_diff_table[TMAP_MAP_OPT_MAX_DIFF_READ_LENGTH]; } // bound differenes by the maximum # of differences if(max_diff < max_mm) max_mm = max_diff; if(max_diff < max_gapo) max_gapo = max_diff; //if(max_diff < max_gape) max_gape = max_diff; best_score = next_best_score = aln_score(max_mm+1, max_gapo+1, max_gape+1, opt); // check whether there are too many N for(j=bases->l-seed2_len,num_n=0;j<bases->l;j++) { if(3 < bases->s[j]) { num_n++; } } if(max_mm < num_n || max_diff < num_n) { return tmap_map_sams_init(NULL); } // initialize sams = tmap_map_sams_init(NULL); occs = NULL; match_sa_start.offset = 0; match_sa_start.hi = 0; match_sa_start.k = 0; match_sa_start.l = bwt->seq_len; stack = tmap_map1_aux_stack_reset(stack, max_mm, max_gapo, max_gape, opt); // reset stack tmap_map1_aux_stack_push(stack, bases->l, &match_sa_start, 0, 0, 0, STATE_M, 0, NULL, opt); while(0 < tmap_map1_aux_stack_size(stack) && tmap_map1_aux_stack_size(stack) < opt->max_entries) { tmap_map1_aux_stack_entry_t *e = NULL; int32_t len=-1; int32_t n_seed_mm=0, offset, width_cur_i; const uint8_t *str=NULL; int32_t sam_found, m; tmap_bwt_match_width_t *width_cur = NULL; const tmap_bwt_match_width_t *seed_width_cur = NULL; tmap_bwt_match_occ_t match_sa_cur, match_sa_next[4]; // get the best entry e = tmap_map1_aux_stack_pop(stack); // bound with best score if(best_score + max_edit_score < e->score) { break; // no need to continue } // some more information match_sa_cur = e->match_sa; // check if we have too many edits m = max_diff - (e->n_mm + e->n_gapo + e->n_gape); if(m < 0) { continue; // too many edits } // get the rest of the information offset = e->offset; // zero-based str = (uint8_t*)bases->s; len = bases->l; width_cur = width; width_cur_i = seed2_len - (len - offset); if(NULL != seed_width) { seed_width_cur = seed_width; n_seed_mm = seed_max_diff - (e->n_mm + e->n_gapo + e->n_gape); // consider only mismatches in the seed } else { seed_width_cur = NULL; } if(0 < width_cur_i && m < width_cur[width_cur_i-1].bid) { // too many edits continue; } // check whether a sam is found sam_found = 0; if(len - seed2_len == offset) { sam_found = 1; } else if(max_mm == e->n_mm // no mismatches from any state && ((e->state == STATE_M && max_gapo == e->n_gapo) // in STATE_M but no more gap opens || (e->state != STATE_M && max_gape == e->n_gape))) { // in STATE_I/STATE_D but no more extensions if(0 < tmap_bwt_match_hash_exact_alt_reverse(bwt, offset, str, &match_sa_cur, hash)) { // the alignment must match exactly to sam sam_found = 2; } else { continue; // no sam, skip } } if(0 < sam_found) { // alignment found // check for duplicates if(0 < sams->n) { for(i=0;i<sams->n;i++) { // check contained if(match_sa_cur.k <= occs[i].k && occs[i].k <= match_sa_cur.l) { // MK <= SK <= ML if(occs[i].l <= match_sa_cur.l) { // MK <= SK <= SL <= ML // Want (SK - MK) + (ML - SL) k = occs[i].k - match_sa_cur.k; // (SK - MK) k += match_sa_cur.l - occs[i].l; // (ML - SL) occs[i].l = match_sa_cur.l; // Make SL = ML } else { // MK <= SK <= ML <= SL k = occs[i].k - match_sa_cur.k; // (SK - MK) } occs[i].k = match_sa_cur.k; // Make SK = MK break; } else if(match_sa_cur.k <= occs[i].l && occs[i].l <= match_sa_cur.l) { // MK <= SL <= ML if(match_sa_cur.k <= occs[i].k) { // MK <= SK <= SL <= ML // Want (SK - MK) + (ML - SL) k = occs[i].k - match_sa_cur.k; // (SK - MK) k += match_sa_cur.l - occs[i].l; // (ML - SL) occs[i].k = match_sa_cur.k; // Make SK = MK } else { // SK <= MK <= SL <= ML k = match_sa_cur.l - occs[i].l; // (ML - SL) } occs[i].l = match_sa_cur.l; // Make SL = ML break; } } if(i < sams->n) { // shadow if(0 < k) { //tmap_map1_aux_stack_shadow(k, bwt->seq_len, e->last_diff_offset, width_cur); width_cur_i = seed2_len - (len - e->last_diff_offset); tmap_map1_aux_stack_shadow(k, seed2_len, width_cur_i, width_cur); } sam_found = 0; continue; } } int32_t score = aln_score(e->n_mm, e->n_gapo, e->n_gape, opt); int32_t do_add = 1; if(sams->n == 0) { best_score = score; best_cnt = 0; best_diff = e->n_mm + e->n_gapo + e->n_gape; } if(score == best_score) { best_cnt += match_sa_cur.l - match_sa_cur.k + 1; } else { if(best_diff + 1 <= max_diff) { max_diff = best_diff + 1; } if(score < next_best_score) { next_best_score = score; } else if(next_best_score < score) { // no need to examine further break; } } if(do_add) { // append uint32_t op, op_len, cigar_i; tmap_map_sam_t *sam = NULL; tmap_map1_aux_stack_entry_t *cur = NULL; tmap_map_sams_realloc(sams, sams->n+1); occs = tmap_realloc(occs, sizeof(tmap_map1_aux_occ_t) * sams->n, "occs"); sam = &sams->sams[sams->n-1]; sam->algo_id = TMAP_MAP_ALGO_MAP1; sam->algo_stage = 0; sam->score = e->score; // aux data tmap_map_sam_malloc_aux(sam); k = occs[sams->n-1].k = match_sa_cur.k; l = occs[sams->n-1].l= match_sa_cur.l; sam->aux.map1_aux->n_mm = e->n_mm; sam->aux.map1_aux->n_gapo = e->n_gapo; sam->aux.map1_aux->n_gape = e->n_gape; // aux data: reference length cur = e; i = e->i; sam->aux.map1_aux->aln_ref = 0; cigar_i = 0; if(2 == sam_found) { // we used 'tmap_bwt_match_exact_alt_reverse' op = STATE_M; op_len = offset; } else { op = -1; op_len = 0; } while(0 <= i) { cur = stack->entry_pool[i]; if(len == cur->offset) break; if(op != cur->state) { if(STATE_M == op || STATE_D == op) { sam->aux.map1_aux->aln_ref += op_len; } op = cur->state; op_len = 1; } else { op_len++; } //fprintf(stderr, "cur->state=%c op_len=%d cur->prev_i=%d k=%u l=%u\n", "MIDS"[cur->state], op_len, cur->prev_i, cur->match_sa.k, cur->match_sa.l); i = cur->prev_i; } if(STATE_M == op || STATE_D == op) { sam->aux.map1_aux->aln_ref += op_len; } /* fprintf(stderr, "shadow 2 k=%u l=%u len=%d offset=%d last_diff_offset=%d\n", k, l, len, offset, e->last_diff_offset); fprintf(stderr, "e->n_mm=%d e->n_gapo=%d e->n_gape=%d\n", e->n_mm, e->n_gapo, e->n_gape); */ //tmap_map1_aux_stack_shadow(l - k + 1, bwt->seq_len, e->last_diff_offset, width_cur); width_cur_i = seed2_len - (len - e->last_diff_offset); tmap_map1_aux_stack_shadow(l - k + 1, seed2_len, width_cur_i, width_cur); if(opt->max_best_cals < best_cnt) { // ignore if too many "best" have been found occs[sams->n-1].l -= (best_cnt - opt->max_best_cals); // only save the maximum break; } } } else { int32_t allow_diff = 1, allow_mm = (e->n_mm < max_mm) ? 1 : 0; // decrement the offset offset--; // use a bound for mismatches if(0 < offset) { int32_t seed_width_cur_i = offset - (len - opt->seed_length); width_cur_i = seed2_len - (len - offset); if(0 < width_cur_i) { if(m-1 < width_cur[width_cur_i-1].bid) { allow_diff = 0; } else if(width_cur[width_cur_i-1].bid == m-1 && width_cur[width_cur_i].bid == m-1 && width_cur[width_cur_i-1].w == width_cur[width_cur_i].w) { allow_mm = 0; } } if(0 < seed_width_cur_i) { if(NULL != seed_width_cur && 0 < seed_width_cur_i) { if(n_seed_mm-1 < seed_width_cur[seed_width_cur_i-1].bid) { allow_diff = 0; } else if(seed_width_cur[seed_width_cur_i-1].bid == n_seed_mm-1 && seed_width_cur[seed_width_cur_i].bid == n_seed_mm-1 && seed_width_cur[seed_width_cur_i-1].w == seed_width_cur[seed_width_cur_i].w) { allow_mm = 0; } } } } // retrieve the next SA interval tmap_bwt_match_hash_2occ4(bwt, &e->match_sa, match_sa_next, hash); // insertions/deletions if(allow_diff && opt->indel_ends_bound + e->n_gapo + e->n_gape <= offset && opt->indel_ends_bound + e->n_gapo + e->n_gape <= len - offset) { // check to add gaps if(STATE_M == e->state) { // gap open if(e->n_gapo < max_gapo) { // gap open is allowed // insertion tmap_map1_aux_stack_push(stack, offset, &match_sa_cur, e->n_mm, e->n_gapo + 1, e->n_gape, STATE_I, 1, e, opt); // deletion for(j = 0; j != 4; ++j) { if(match_sa_next[j].k <= match_sa_next[j].l) { // remember that a gap deletion does not consume a // read base, so use 'offset+1' tmap_map1_aux_stack_push(stack, offset+1, &match_sa_next[j], e->n_mm, e->n_gapo + 1, e->n_gape, STATE_D, 1, e, opt); } } } } else if(STATE_I == e->state) { // extension of an insertion if(e->n_gape < max_gape) { // gap extension is allowed tmap_map1_aux_stack_push(stack, offset, &match_sa_cur, e->n_mm, e->n_gapo, e->n_gape + 1, STATE_I, 1, e, opt); } } else if(STATE_D == e->state) { // extension of a deletion if(e->n_gape < max_gape) { if(e->n_gape + e->n_gapo < max_diff || e->match_sa.l - e->match_sa.k + 1 < opt->max_cals_del) { // gap extension is allowed for(j = 0; j != 4; ++j) { if(match_sa_next[j].k <= match_sa_next[j].l) { // remember that a gap deletion does not consume a // read base, so use 'offset+1' tmap_map1_aux_stack_push(stack, offset+1, &match_sa_next[j], e->n_mm, e->n_gapo, e->n_gape + 1, STATE_D, 1, e, opt); } } } } } } // mismatches if(1 == allow_mm && 1 == allow_diff) { // mismatches allowed for(j=0;j<4;j++) { int32_t c = (str[offset] + j) & 3; int32_t is_mm = (0 < j || 3 < str[offset]); if(match_sa_next[c].k <= match_sa_next[c].l) { tmap_map1_aux_stack_push(stack, offset, &match_sa_next[c], e->n_mm + is_mm, e->n_gapo, e->n_gape, STATE_M, is_mm, e, opt); } } } else if(str[offset] < 4) { // try exact match only int32_t c = str[offset] & 3; if(match_sa_next[c].k <= match_sa_next[c].l) { tmap_map1_aux_stack_push(stack, offset, &match_sa_next[c], e->n_mm, e->n_gapo, e->n_gape, STATE_M, 0, e, opt); } } } } return tmap_map1_sam_to_real(sams, occs, bases, seed2_len, refseq, bwt, sa, hash, opt); }
inline int32_t tmap_seq_get_bases_length(tmap_seq_t *seq) { return tmap_seq_get_bases(seq)->l; }
// init sams = tmap_map_sams_init(NULL); // update the seed length based on the read length seed_length = opt->seed_length; if(0 == opt->seed_length_set) { i = tmap_seq_get_bases_length(seq); while(0 < i) { seed_length++; i >>= 1; // divide by two } } // check that the sequence is long enough bases = tmap_seq_get_bases(seq); seq_len = bases->l; if(seq_len - seed_length < 0) { return sams; } // seeds bases = tmap_seq_get_bases(seq); query = (uint8_t*)bases->s; n_seeds = 0; // pre-allocate mmemory if(0 < opt->seed_step) { m_seeds = 0; int32_t k; for(j=seed_length,k=0;j<=seq_len;j+=opt->seed_step,k++) {
inline void tmap_sam_print_mapped(tmap_file_t *fp, tmap_seq_t *seq, int32_t sam_flowspace_tags, int32_t bidirectional, int32_t seq_eq, tmap_refseq_t *refseq, uint8_t strand, uint32_t seqid, uint32_t pos, int32_t aln_num, uint32_t end_num, uint32_t m_unmapped, uint32_t m_prop, double m_num_std, uint32_t m_strand, uint32_t m_seqid, uint32_t m_pos, uint32_t m_tlen, uint8_t mapq, uint32_t *cigar, int32_t n_cigar, int32_t score, int32_t ascore, int32_t pscore, int32_t nh, int32_t algo_id, int32_t algo_stage, const char *format, ...) { va_list ap; int32_t i; tmap_string_t *name=NULL, *bases=NULL, *qualities=NULL; char *bases_eq=NULL; uint32_t flag; tmap_string_t *md; int32_t nm; /* fprintf(stderr, "end_num=%d m_unmapped=%d m_prop=%d m_strand=%d m_seqid=%d m_pos=%d m_tlen=%d\n", end_num, m_unmapped, m_prop, m_strand, m_seqid, m_pos, m_tlen); */ name = tmap_seq_get_name(seq); bases = tmap_seq_get_bases(seq); qualities = tmap_seq_get_qualities(seq); if(1 == strand) { // reverse for the output tmap_string_reverse_compliment(bases, 0); tmap_string_reverse(qualities); } if(0 == pos + 1) { tmap_error("position is out of range", Exit, OutOfRange); } // compute the MD/NM if(1 == seq_eq && 0 < bases->l) { bases_eq = tmap_calloc((1 + bases->l), sizeof(char), "bases_eq"); } else { bases_eq = NULL; } md = tmap_sam_md(refseq, bases->s, seqid, pos, cigar, n_cigar, &nm, bases_eq); // flag flag = 0; if(1 == strand) flag |= 0x10; // strand if(0 < aln_num) flag |= 0x100; // secondary alignment if(0 < end_num) { // mate info flag |= 0x1; if(0 == m_unmapped && 1 == m_prop) flag |= 0x2; // properly aligned if(1 == m_unmapped) flag |= 0x8; // unmapped else if(1 == m_strand) flag |= 0x20; // strand flag |= (1 == end_num) ? 0x40 : 0x80; // first/second end } tmap_file_fprintf(fp, "%s\t%u\t%s\t%u\t%u\t", name->s, flag, refseq->annos[seqid].name->s, pos + 1, mapq); // print out the cigar if(TMAP_SEQ_TYPE_SFF == seq->type) { if(0 == strand && 0 < seq->data.sff->rheader->clip_left) { tmap_file_fprintf(fp, "%dH", seq->data.sff->rheader->clip_left); } else if(1 == strand && 0 < seq->data.sff->rheader->clip_right) { tmap_file_fprintf(fp, "%dH", seq->data.sff->rheader->clip_right); } } for(i=0;i<n_cigar;i++) { tmap_file_fprintf(fp, "%d%c", cigar[i]>>4, "MIDNSHP"[cigar[i]&0xf]); } if(TMAP_SEQ_TYPE_SFF == seq->type) { if(1 == strand && 0 < seq->data.sff->rheader->clip_left) { tmap_file_fprintf(fp, "%dH", seq->data.sff->rheader->clip_left); } else if(0 == strand && 0 < seq->data.sff->rheader->clip_right) { tmap_file_fprintf(fp, "%dH", seq->data.sff->rheader->clip_right); } } // mate info if(0 == end_num) { // no mate tmap_file_fprintf(fp, "\t*\t0\t0"); } else if(1 == m_unmapped) { // unmapped mate tmap_file_fprintf(fp, "\t%s\t%u\t%u", "=", pos + 1, 0); } else { // mapped mate tmap_file_fprintf(fp, "\t%s\t%u\t%d", refseq->annos[m_seqid].name->s, m_pos+1, m_tlen); } // bases and qualities if(1 == seq_eq && NULL != bases_eq) { tmap_file_fprintf(fp, "\t%s\t%s", bases_eq, (0 == qualities->l) ? "*" : qualities->s); } else { tmap_file_fprintf(fp, "\t%s\t%s", bases->s, (0 == qualities->l) ? "*" : qualities->s); } // RG tmap_sam_print_rg(fp, seq); // PG tmap_file_fprintf(fp, "\tPG:Z:%s", PACKAGE_NAME); // MD and NM tmap_file_fprintf(fp, "\tMD:Z:%s\tNM:i:%d", md->s, nm); // AS tmap_file_fprintf(fp, "\tAS:i:%d", score); // NH if(1 < nh) tmap_file_fprintf(fp, "\tNH:i:%d", nh); // FZ and ZF if(1 == sam_flowspace_tags) { tmap_sam_print_fz_and_zf(fp, seq); } // XA if(0 < algo_stage) { tmap_file_fprintf(fp, "\tXA:Z:%s-%d", tmap_algo_id_to_name(algo_id), algo_stage); } // XZ if(TMAP_SEQ_TYPE_SFF == seq->type && INT32_MIN != ascore) { tmap_file_fprintf(fp, "\tXZ:i:%d", ascore); } if(0 < end_num) { // mate info tmap_file_fprintf(fp, "\tYP:i:%d", pscore); if(0 == m_unmapped) { tmap_file_fprintf(fp, "\tYS:f:%f", m_num_std); } } if(1 == bidirectional) { tmap_file_fprintf(fp, "\tXB:i:1"); } // optional tags if(NULL != format) { va_start(ap, format); tmap_file_vfprintf(fp, format, ap); va_end(ap); } // new line tmap_file_fprintf(fp, "\n"); if(1 == strand) { // reverse back tmap_string_reverse_compliment(bases, 0); tmap_string_reverse(qualities); } // free tmap_string_destroy(md); free(bases_eq); }
inline void tmap_sam_print_unmapped(tmap_file_t *fp, tmap_seq_t *seq, int32_t sam_flowspace_tags, int32_t bidirectional, tmap_refseq_t *refseq, uint32_t end_num, uint32_t m_unmapped, uint32_t m_prop, uint32_t m_strand, uint32_t m_seqid, uint32_t m_pos, const char *format, ...) { uint32_t flag = 0; tmap_string_t *name=NULL, *bases=NULL, *qualities=NULL; va_list ap; name = tmap_seq_get_name(seq); bases = tmap_seq_get_bases(seq); qualities = tmap_seq_get_qualities(seq); // set the flag flag = 0x4; if(0 < end_num) { // mate info flag |= 0x1; if(1 == m_prop) flag |= 0x2; // properly aligned if(1 == m_unmapped) flag |= 0x8; // unmapped else if(1 == m_strand) flag |= 0x20; // strand flag |= (1 == end_num) ? 0x40 : 0x80; // first/second end } // name, flag, seqid, pos, mapq, cigar tmap_file_fprintf(fp, "%s\t%u\t*\t%u\t%u\t*", name->s, flag, 0, 0); // NB: hard clipped portions of the read is not reported // mate info if(0 == end_num) { // no mate tmap_file_fprintf(fp, "\t*\t0\t0"); } else if(1 == m_unmapped) { // unmapped mate tmap_file_fprintf(fp, "\t*\t0\t0"); } else if(NULL != refseq) { // mapped mate tmap_file_fprintf(fp, "\t%s\t%u\t%u", refseq->annos[m_seqid].name->s, m_pos+1, 0); } // bases and qual tmap_file_fprintf(fp, "\t%s\t%s", (0 == bases->l) ? "*" : bases->s, (0 == qualities->l) ? "*" : qualities->s); // RG tmap_sam_print_rg(fp, seq); // PG tmap_file_fprintf(fp, "\tPG:Z:%s", PACKAGE_NAME); // FZ and ZF if(1 == sam_flowspace_tags) { tmap_sam_print_fz_and_zf(fp, seq); } if(1 == bidirectional) { tmap_file_fprintf(fp, "\tXB:i:1"); } // optional tags if(NULL != format) { va_start(ap, format); tmap_file_vfprintf(fp, format, ap); va_end(ap); } tmap_file_fprintf(fp, "\n"); }