minibwa 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/ext/minibwa/extconf.rb +105 -0
- data/ext/minibwa/mb_buffer.c +113 -0
- data/ext/minibwa/mb_hit.c +192 -0
- data/ext/minibwa/mb_index.c +462 -0
- data/ext/minibwa/mb_index_build.c +174 -0
- data/ext/minibwa/mb_options.c +301 -0
- data/ext/minibwa/minibwa/LICENSE.txt +37 -0
- data/ext/minibwa/minibwa/align.c +930 -0
- data/ext/minibwa/minibwa/bseq.h +45 -0
- data/ext/minibwa/minibwa/bwt.c +715 -0
- data/ext/minibwa/minibwa/bwt.h +86 -0
- data/ext/minibwa/minibwa/cs.c +161 -0
- data/ext/minibwa/minibwa/format.c +356 -0
- data/ext/minibwa/minibwa/index.c +342 -0
- data/ext/minibwa/minibwa/kalloc.c +224 -0
- data/ext/minibwa/minibwa/kalloc.h +54 -0
- data/ext/minibwa/minibwa/ketopt.h +123 -0
- data/ext/minibwa/minibwa/kommon.c +374 -0
- data/ext/minibwa/minibwa/kommon.h +85 -0
- data/ext/minibwa/minibwa/kseq.h +256 -0
- data/ext/minibwa/minibwa/ksort.h +163 -0
- data/ext/minibwa/minibwa/ksw2.h +220 -0
- data/ext/minibwa/minibwa/ksw2_extd2_sse.c +403 -0
- data/ext/minibwa/minibwa/ksw2_extz2_sse.c +296 -0
- data/ext/minibwa/minibwa/ksw2_ll_sse.c +341 -0
- data/ext/minibwa/minibwa/kthread.h +15 -0
- data/ext/minibwa/minibwa/l2bit.c +479 -0
- data/ext/minibwa/minibwa/l2bit.h +72 -0
- data/ext/minibwa/minibwa/lchain.c +231 -0
- data/ext/minibwa/minibwa/libsais.c +6985 -0
- data/ext/minibwa/minibwa/libsais.h +106 -0
- data/ext/minibwa/minibwa/libsais64.c +7064 -0
- data/ext/minibwa/minibwa/libsais64.h +81 -0
- data/ext/minibwa/minibwa/map-algo.c +769 -0
- data/ext/minibwa/minibwa/mbpriv.h +148 -0
- data/ext/minibwa/minibwa/minibwa.h +176 -0
- data/ext/minibwa/minibwa/options.c +116 -0
- data/ext/minibwa/minibwa/pe.c +559 -0
- data/ext/minibwa/minibwa/s2n-lite.h +59 -0
- data/ext/minibwa/minibwa/seed.c +354 -0
- data/ext/minibwa/minibwa.c +67 -0
- data/ext/minibwa/minibwa.h +51 -0
- data/lib/minibwa/hit.rb +110 -0
- data/lib/minibwa/index.rb +77 -0
- data/lib/minibwa/options.rb +235 -0
- data/lib/minibwa/sam.rb +85 -0
- data/lib/minibwa/version.rb +6 -0
- data/lib/minibwa.rb +11 -0
- metadata +88 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#ifndef MB_BWT_H
|
|
2
|
+
#define MB_BWT_H
|
|
3
|
+
|
|
4
|
+
#include <stdint.h>
|
|
5
|
+
#include <stddef.h>
|
|
6
|
+
|
|
7
|
+
#define MB_MAGIC "MBW\2"
|
|
8
|
+
|
|
9
|
+
typedef struct {
|
|
10
|
+
uint64_t x[2];
|
|
11
|
+
uint64_t size, info;
|
|
12
|
+
} mb_sai_t;
|
|
13
|
+
|
|
14
|
+
typedef struct {
|
|
15
|
+
uint64_t primary; // S^{-1}(0), or the primary index of BWT
|
|
16
|
+
uint64_t L2[5]; // C(), cumulative count
|
|
17
|
+
uint64_t seq_len; // sequence length
|
|
18
|
+
uint64_t data_len;
|
|
19
|
+
uint64_t *data; // BWT
|
|
20
|
+
uint32_t cnt_table[256];
|
|
21
|
+
uint32_t pre_len;
|
|
22
|
+
mb_sai_t *pre;
|
|
23
|
+
// suffix array
|
|
24
|
+
uint32_t sa_bit; // sample rate: 1/(1<<sa_bit)
|
|
25
|
+
uint64_t n_sa;
|
|
26
|
+
uint64_t *sa;
|
|
27
|
+
// mmap
|
|
28
|
+
void *mmap; // mmap pointer
|
|
29
|
+
size_t mmap_len; // mmap length (for munmap)
|
|
30
|
+
} mb_bwt_t;
|
|
31
|
+
|
|
32
|
+
typedef struct { size_t n, m; mb_sai_t *a; } mb_sai_v;
|
|
33
|
+
|
|
34
|
+
typedef struct {
|
|
35
|
+
// input before calling
|
|
36
|
+
int32_t min_len, min_occ;
|
|
37
|
+
int32_t st, en;
|
|
38
|
+
const uint8_t *q;
|
|
39
|
+
mb_sai_v *v; // output; v->n is not set to 0
|
|
40
|
+
// internal state
|
|
41
|
+
int32_t stage;
|
|
42
|
+
int32_t x, i;
|
|
43
|
+
uint32_t kmer; // for k-mer cache
|
|
44
|
+
mb_sai_t p;
|
|
45
|
+
} mb_smem_entry_t;
|
|
46
|
+
|
|
47
|
+
#ifdef __cplusplus
|
|
48
|
+
extern "C" {
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
extern int mb_verbose;
|
|
52
|
+
|
|
53
|
+
mb_bwt_t *mb_bwt_init(void);
|
|
54
|
+
void mb_bwt_destroy(mb_bwt_t *bwt);
|
|
55
|
+
mb_bwt_t *mb_bwt_load_raw(const char *fn); // from raw bwt_gen.c output
|
|
56
|
+
int mb_bwt_save(const char *fn, const mb_bwt_t *bwt);
|
|
57
|
+
mb_bwt_t *mb_bwt_load(const char *fn);
|
|
58
|
+
mb_bwt_t *mb_bwt_load_mmap(const char *fn, int preload);
|
|
59
|
+
mb_bwt_t *mb_bwt_init_from_raw(int is_byte, const void *raw_, uint64_t len, uint64_t primary);
|
|
60
|
+
|
|
61
|
+
void mb_bwt_cache(mb_bwt_t *bwt, int32_t len);
|
|
62
|
+
uint64_t mb_bwt_rank11(const mb_bwt_t *bwt, uint64_t k, uint8_t c);
|
|
63
|
+
void mb_bwt_rank1a(const mb_bwt_t *bwt, uint64_t k, uint64_t cnt[4]);
|
|
64
|
+
void mb_bwt_rank2a(const mb_bwt_t *bwt, uint64_t k, uint64_t l, uint64_t cntk[4], uint64_t cntl[4]);
|
|
65
|
+
|
|
66
|
+
void mb_bwt_extend(const mb_bwt_t *bwt, const mb_sai_t *ik, mb_sai_t ok[4], int is_back);
|
|
67
|
+
void mb_bwt_count_kmer(const mb_bwt_t *bwt, int32_t depth, mb_sai_t *a);
|
|
68
|
+
int64_t mb_bwt_smem(const mb_bwt_t *f, uint32_t len, const uint8_t *q, int64_t x, int64_t min_len, int64_t min_occ, mb_sai_t *p);
|
|
69
|
+
void mb_bwt_smem_batch(void *km, const mb_bwt_t *bwt, int32_t n, mb_smem_entry_t *a);
|
|
70
|
+
|
|
71
|
+
void mb_bwt_gen_sa(mb_bwt_t *bwt, uint32_t sa_bit);
|
|
72
|
+
uint64_t mb_bwt_sa(const mb_bwt_t *bwt, uint64_t k);
|
|
73
|
+
void mb_bwt_sa_batch(void *km, const mb_bwt_t *bwt, int64_t n, uint64_t *x);
|
|
74
|
+
|
|
75
|
+
static inline void mb_bwt_set_intv(const mb_bwt_t *bwt, int c, mb_sai_t *ik)
|
|
76
|
+
{
|
|
77
|
+
ik->x[0] = bwt->L2[c] + 1; // +1 for the missing sentinel
|
|
78
|
+
ik->x[1] = bwt->L2[3-c] + 1;
|
|
79
|
+
ik->size = bwt->L2[c+1] - bwt->L2[c];
|
|
80
|
+
ik->info = 0;
|
|
81
|
+
}
|
|
82
|
+
#ifdef __cplusplus
|
|
83
|
+
}
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
#endif
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#include <assert.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include "mbpriv.h"
|
|
4
|
+
#include "kalloc.h"
|
|
5
|
+
#include "kommon.h"
|
|
6
|
+
|
|
7
|
+
static char *alloc_tmp(void *km, const mb_hit_t *r)
|
|
8
|
+
{
|
|
9
|
+
int32_t i, min_tmp_len = 31;
|
|
10
|
+
for (i = 0; i < (int)r->p->n_cigar; ++i) {
|
|
11
|
+
int op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
|
12
|
+
if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL)
|
|
13
|
+
min_tmp_len = min_tmp_len > len + 5? min_tmp_len : len + 5;
|
|
14
|
+
}
|
|
15
|
+
return Kmalloc(km, char, min_tmp_len + 1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static void write_indel_ds(void *km, kstring_t *str, int64_t len, const uint8_t *seq, int64_t ll, int64_t lr) // write an indel to ds; adapted from minigraph
|
|
19
|
+
{
|
|
20
|
+
int64_t i;
|
|
21
|
+
if (ll + lr >= len) {
|
|
22
|
+
km_sprintf_lite(km, str, "[");
|
|
23
|
+
for (i = 0; i < len; ++i)
|
|
24
|
+
km_sprintf_lite(km, str, "%c", "acgtn"[seq[i]]);
|
|
25
|
+
km_sprintf_lite(km, str, "]");
|
|
26
|
+
} else {
|
|
27
|
+
int64_t k = 0;
|
|
28
|
+
if (ll > 0) {
|
|
29
|
+
km_sprintf_lite(km, str, "[");
|
|
30
|
+
for (i = 0; i < ll; ++i)
|
|
31
|
+
km_sprintf_lite(km, str, "%c", "acgtn"[seq[k+i]]);
|
|
32
|
+
km_sprintf_lite(km, str, "]");
|
|
33
|
+
k += ll;
|
|
34
|
+
}
|
|
35
|
+
for (i = 0; i < len - lr - ll; ++i)
|
|
36
|
+
km_sprintf_lite(km, str, "%c", "acgtn"[seq[k+i]]);
|
|
37
|
+
k += len - lr - ll;
|
|
38
|
+
if (lr > 0) {
|
|
39
|
+
km_sprintf_lite(km, str, "[");
|
|
40
|
+
for (i = 0; i < lr; ++i)
|
|
41
|
+
km_sprintf_lite(km, str, "%c", "acgtn"[seq[k+i]]);
|
|
42
|
+
km_sprintf_lite(km, str, "]");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
void mb_write_cs_ds(void *km, kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mb_hit_t *r, int is_ds)
|
|
48
|
+
{
|
|
49
|
+
int i, q_off, t_off, q_len = 0, t_len = 0;
|
|
50
|
+
char *tmp;
|
|
51
|
+
km_sprintf_lite(km, s, "%cs:Z:", is_ds? 'd' : 'c');
|
|
52
|
+
for (i = 0; i < (int)r->p->n_cigar; ++i) {
|
|
53
|
+
int op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
|
54
|
+
if (op == MB_CIGAR_MATCH || op == MB_CIGAR_EQ_MATCH || op == MB_CIGAR_X_MISMATCH) {
|
|
55
|
+
q_len += len, t_len += len;
|
|
56
|
+
} else if (op == MB_CIGAR_INS) {
|
|
57
|
+
q_len += len;
|
|
58
|
+
} else if (op == MB_CIGAR_DEL || op == MB_CIGAR_N_SKIP) {
|
|
59
|
+
t_len += len;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
tmp = alloc_tmp(km, r);
|
|
63
|
+
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
|
64
|
+
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
|
65
|
+
assert((op >= MB_CIGAR_MATCH && op <= MB_CIGAR_N_SKIP) || op == MB_CIGAR_EQ_MATCH || op == MB_CIGAR_X_MISMATCH);
|
|
66
|
+
if (op == MB_CIGAR_MATCH || op == MB_CIGAR_EQ_MATCH || op == MB_CIGAR_X_MISMATCH) {
|
|
67
|
+
int l_tmp = 0;
|
|
68
|
+
for (j = 0; j < len; ++j) {
|
|
69
|
+
if (qseq[q_off + j] != tseq[t_off + j]) {
|
|
70
|
+
if (l_tmp > 0) {
|
|
71
|
+
km_sprintf_lite(km, s, ":%d", l_tmp);
|
|
72
|
+
l_tmp = 0;
|
|
73
|
+
}
|
|
74
|
+
km_sprintf_lite(km, s, "*%c%c", "acgtn"[tseq[t_off + j]], "acgtn"[qseq[q_off + j]]);
|
|
75
|
+
} else ++l_tmp;
|
|
76
|
+
}
|
|
77
|
+
if (l_tmp > 0)
|
|
78
|
+
km_sprintf_lite(km, s, ":%d", l_tmp);
|
|
79
|
+
q_off += len, t_off += len;
|
|
80
|
+
} else if (op == MB_CIGAR_INS) {
|
|
81
|
+
if (is_ds) {
|
|
82
|
+
int z, ll, lr, y = q_off;
|
|
83
|
+
for (z = 1; z <= len; ++z)
|
|
84
|
+
if (y - z < 0 || qseq[y + len - z] != qseq[y - z])
|
|
85
|
+
break;
|
|
86
|
+
lr = z - 1;
|
|
87
|
+
for (z = 0; z < len; ++z)
|
|
88
|
+
if (y + len + z >= q_len || qseq[y + len + z] != qseq[y + z])
|
|
89
|
+
break;
|
|
90
|
+
ll = z;
|
|
91
|
+
km_sprintf_lite(km, s, "+");
|
|
92
|
+
write_indel_ds(km, s, len, &qseq[y], ll, lr);
|
|
93
|
+
} else {
|
|
94
|
+
for (j = 0, tmp[len] = 0; j < len; ++j)
|
|
95
|
+
tmp[j] = "acgtn"[qseq[q_off + j]];
|
|
96
|
+
km_sprintf_lite(km, s, "+%s", tmp);
|
|
97
|
+
}
|
|
98
|
+
q_off += len;
|
|
99
|
+
} else if (op == MB_CIGAR_DEL) {
|
|
100
|
+
if (is_ds) {
|
|
101
|
+
int z, ll, lr, x = t_off;
|
|
102
|
+
for (z = 1; z <= len; ++z)
|
|
103
|
+
if (x - z < 0 || tseq[x + len - z] != tseq[x - z])
|
|
104
|
+
break;
|
|
105
|
+
lr = z - 1;
|
|
106
|
+
for (z = 0; z < len; ++z)
|
|
107
|
+
if (x + len + z >= t_len || tseq[x + z] != tseq[x + len + z])
|
|
108
|
+
break;
|
|
109
|
+
ll = z;
|
|
110
|
+
km_sprintf_lite(km, s, "-");
|
|
111
|
+
write_indel_ds(km, s, len, &tseq[x], ll, lr);
|
|
112
|
+
} else {
|
|
113
|
+
for (j = 0, tmp[len] = 0; j < len; ++j)
|
|
114
|
+
tmp[j] = "acgtn"[tseq[t_off + j]];
|
|
115
|
+
km_sprintf_lite(km, s, "-%s", tmp);
|
|
116
|
+
}
|
|
117
|
+
t_off += len;
|
|
118
|
+
} else { // intron
|
|
119
|
+
assert(len >= 2);
|
|
120
|
+
km_sprintf_lite(km, s, "~%c%c%d%c%c", "acgtn"[tseq[t_off]], "acgtn"[tseq[t_off+1]],
|
|
121
|
+
len, "acgtn"[tseq[t_off+len-2]], "acgtn"[tseq[t_off+len-1]]);
|
|
122
|
+
t_off += len;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
kfree(km, tmp);
|
|
126
|
+
assert(t_off == r->te - r->ts && q_off == r->qe - r->qs);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
void mb_write_MD(void *km, kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mb_hit_t *r)
|
|
130
|
+
{
|
|
131
|
+
int i, q_off, t_off, l_MD = 0;
|
|
132
|
+
char *tmp;
|
|
133
|
+
km_sprintf_lite(km, s, "MD:Z:");
|
|
134
|
+
tmp = alloc_tmp(km, r);
|
|
135
|
+
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
|
136
|
+
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
|
137
|
+
assert((op >= MB_CIGAR_MATCH && op <= MB_CIGAR_N_SKIP) || op == MB_CIGAR_EQ_MATCH || op == MB_CIGAR_X_MISMATCH);
|
|
138
|
+
if (op == MB_CIGAR_MATCH || op == MB_CIGAR_EQ_MATCH || op == MB_CIGAR_X_MISMATCH) {
|
|
139
|
+
for (j = 0; j < len; ++j) {
|
|
140
|
+
if (qseq[q_off + j] != tseq[t_off + j]) {
|
|
141
|
+
km_sprintf_lite(km, s, "%d%c", l_MD, "ACGTN"[tseq[t_off + j]]);
|
|
142
|
+
l_MD = 0;
|
|
143
|
+
} else ++l_MD;
|
|
144
|
+
}
|
|
145
|
+
q_off += len, t_off += len;
|
|
146
|
+
} else if (op == MB_CIGAR_INS) {
|
|
147
|
+
q_off += len;
|
|
148
|
+
} else if (op == MB_CIGAR_DEL) {
|
|
149
|
+
for (j = 0, tmp[len] = 0; j < len; ++j)
|
|
150
|
+
tmp[j] = "ACGTN"[tseq[t_off + j]];
|
|
151
|
+
km_sprintf_lite(km, s, "%d^%s", l_MD, tmp);
|
|
152
|
+
l_MD = 0;
|
|
153
|
+
t_off += len;
|
|
154
|
+
} else if (op == MB_CIGAR_N_SKIP) {
|
|
155
|
+
t_off += len;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (l_MD > 0) km_sprintf_lite(km, s, "%d", l_MD);
|
|
159
|
+
kfree(km, tmp);
|
|
160
|
+
assert(t_off == r->te - r->ts && q_off == r->qe - r->qs);
|
|
161
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
#include <stdio.h>
|
|
2
|
+
#include <stdlib.h>
|
|
3
|
+
#include <assert.h>
|
|
4
|
+
#include "mbpriv.h"
|
|
5
|
+
#include "kommon.h"
|
|
6
|
+
|
|
7
|
+
static char mb_rg_id[256];
|
|
8
|
+
|
|
9
|
+
/**************
|
|
10
|
+
* PAF output *
|
|
11
|
+
**************/
|
|
12
|
+
|
|
13
|
+
static inline void write_tags(kstring_t *s, const mb_hit_t *p)
|
|
14
|
+
{
|
|
15
|
+
int32_t nm = p->blen - p->mlen + p->p->n_ambi;
|
|
16
|
+
kom_sprintf_lite(s, "\tNM:i:%d\tAS:i:%d\tms:i:%d\tmd:i:%d", nm, p->p->dp_score, p->p->dp_max0, p->p->dp_max - p->p->dp_max2);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void mb_fmt_paf(kstring_t *s, const l2b_t *l2b, const mb_bseq1_t *t, const mb_hit_t *p, uint64_t opt_flag, int n_seg, int seg_idx)
|
|
20
|
+
{
|
|
21
|
+
kom_sprintf_lite(s, "%s", t->name);
|
|
22
|
+
if (n_seg > 1 && seg_idx >= 0)
|
|
23
|
+
kom_sprintf_lite(s, "/%d", seg_idx + 1);
|
|
24
|
+
kom_sprintf_lite(s, "\t%ld", (long)t->l_seq);
|
|
25
|
+
if (p == 0) { // for unmapped reads
|
|
26
|
+
kom_sprintf_lite(s, "\t*\t*\t*\t*\t*\t*\t*\t0\t0\t0\n");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
kom_sprintf_lite(s, "\t%d\t%d\t%c\t%s\t%ld\t%ld\t%ld\t%d\t%d\t%d\ttp:A:%c\ts1:i:%d\tcm:i:%d",
|
|
30
|
+
p->qs, p->qe, p->rev? '-' : '+', l2b->ctg[p->tid].name, (long)l2b->ctg[p->tid].len, (long)p->ts, (long)p->te,
|
|
31
|
+
p->mlen, p->blen, p->mapq, p->parent == p->id? 'P' : 'S', p->score, p->cnt);
|
|
32
|
+
if (p->parent == p->id) kom_sprintf_lite(s, "\ts2:i:%d", p->subsc >= 0? p->subsc : 0);
|
|
33
|
+
if (p->p) {
|
|
34
|
+
write_tags(s, p);
|
|
35
|
+
if (p->p->n_cigar > 0) {
|
|
36
|
+
int32_t i;
|
|
37
|
+
kom_sprintf_lite(s, "\tcg:Z:");
|
|
38
|
+
for (i = 0; i < p->p->n_cigar; ++i)
|
|
39
|
+
kom_sprintf_lite(s, "%d%c", p->p->cigar[i]>>4, MB_CIGAR_STR[p->p->cigar[i]&0xf]);
|
|
40
|
+
}
|
|
41
|
+
if (p->p->cs) kom_sprintf_lite(s, "\t%s", (char*)&p->p->cigar[p->p->n_cigar]);
|
|
42
|
+
}
|
|
43
|
+
if ((opt_flag & MB_F_COPY_COMMENT) && t->comment)
|
|
44
|
+
kom_sprintf_lite(s, "\t%s", t->comment);
|
|
45
|
+
kom_sprintf_lite(s, "\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**************
|
|
49
|
+
* SAM header *
|
|
50
|
+
**************/
|
|
51
|
+
|
|
52
|
+
char *mb_escape(char *s)
|
|
53
|
+
{
|
|
54
|
+
char *p, *q;
|
|
55
|
+
for (p = q = s; *p; ++p) {
|
|
56
|
+
if (*p == '\\') {
|
|
57
|
+
++p;
|
|
58
|
+
if (*p == 't') *q++ = '\t';
|
|
59
|
+
else if (*p == 'n') *q++ = '\n';
|
|
60
|
+
else if (*p == 'r') *q++ = '\r';
|
|
61
|
+
else if (*p == '\\') *q++ = '\\';
|
|
62
|
+
else if (*p == '\0') break;
|
|
63
|
+
} else *q++ = *p;
|
|
64
|
+
}
|
|
65
|
+
*q = '\0';
|
|
66
|
+
return s;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static int sam_write_rg_line(kstring_t *str, const char *s)
|
|
70
|
+
{
|
|
71
|
+
char *p, *q, *r, *rg_line = 0;
|
|
72
|
+
memset(mb_rg_id, 0, 256);
|
|
73
|
+
if (s == 0) return 0;
|
|
74
|
+
if (strstr(s, "@RG") != s) {
|
|
75
|
+
if (kom_verbose >= 1) fprintf(stderr, "[ERROR] the read group line is not started with @RG\n");
|
|
76
|
+
goto err_set_rg;
|
|
77
|
+
}
|
|
78
|
+
if (strstr(s, "\t") != NULL) {
|
|
79
|
+
if (kom_verbose >= 1) fprintf(stderr, "[ERROR] the read group line contained literal <tab> characters -- replace with escaped tabs: \\t\n");
|
|
80
|
+
goto err_set_rg;
|
|
81
|
+
}
|
|
82
|
+
rg_line = kom_strdup(s);
|
|
83
|
+
mb_escape(rg_line);
|
|
84
|
+
if ((p = strstr(rg_line, "\tID:")) == 0) {
|
|
85
|
+
if (kom_verbose >= 1) fprintf(stderr, "[ERROR] no ID within the read group line\n");
|
|
86
|
+
goto err_set_rg;
|
|
87
|
+
}
|
|
88
|
+
p += 4;
|
|
89
|
+
for (q = p; *q && *q != '\t' && *q != '\n'; ++q);
|
|
90
|
+
if (q - p + 1 > 256) {
|
|
91
|
+
if (kom_verbose >= 1) fprintf(stderr, "[ERROR] @RG:ID is longer than 255 characters\n");
|
|
92
|
+
goto err_set_rg;
|
|
93
|
+
}
|
|
94
|
+
for (q = p, r = mb_rg_id; *q && *q != '\t' && *q != '\n'; ++q)
|
|
95
|
+
*r++ = *q;
|
|
96
|
+
kom_sprintf_lite(str, "%s\n", rg_line);
|
|
97
|
+
free(rg_line);
|
|
98
|
+
return 0;
|
|
99
|
+
|
|
100
|
+
err_set_rg:
|
|
101
|
+
free(rg_line);
|
|
102
|
+
return -1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
int mb_fmt_sam_hdr(kstring_t *str, const l2b_t *idx, const char *rg, const char *ver, int argc, char *argv[])
|
|
106
|
+
{
|
|
107
|
+
int i, ret = 0;
|
|
108
|
+
str->l = 0;
|
|
109
|
+
kom_sprintf_lite(str, "@HD\tVN:1.6\tSO:unsorted\tGO:query\n");
|
|
110
|
+
if (idx)
|
|
111
|
+
for (i = 0; i < idx->n_ctg; ++i)
|
|
112
|
+
kom_sprintf_lite(str, "@SQ\tSN:%s\tLN:%ld\n", idx->ctg[i].name, idx->ctg[i].len);
|
|
113
|
+
if (rg) ret = sam_write_rg_line(str, rg);
|
|
114
|
+
kom_sprintf_lite(str, "@PG\tID:minibwa\tPN:minibwa");
|
|
115
|
+
if (ver) kom_sprintf_lite(str, "\tVN:%s", ver);
|
|
116
|
+
if (argc > 1) {
|
|
117
|
+
kom_sprintf_lite(str, "\tCL:minibwa");
|
|
118
|
+
for (i = 0; i < argc; ++i)
|
|
119
|
+
kom_sprintf_lite(str, " %s", argv[i]);
|
|
120
|
+
}
|
|
121
|
+
kom_sprintf_lite(str, "\n");
|
|
122
|
+
return ret;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**************
|
|
126
|
+
* SAM output *
|
|
127
|
+
**************/
|
|
128
|
+
|
|
129
|
+
static inline void str_enlarge(kstring_t *s, int l)
|
|
130
|
+
{
|
|
131
|
+
if (s->l + l + 1 > s->m) {
|
|
132
|
+
s->m = s->l + l + 1;
|
|
133
|
+
kom_roundup64(s->m);
|
|
134
|
+
s->s = kom_realloc(char, s->s, s->m);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
static inline void str_copy(kstring_t *s, const char *st, const char *en)
|
|
139
|
+
{
|
|
140
|
+
str_enlarge(s, en - st);
|
|
141
|
+
memcpy(&s->s[s->l], st, en - st);
|
|
142
|
+
s->l += en - st;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
static void sam_write_sq(kstring_t *s, char *seq, int l, int rev, int comp)
|
|
146
|
+
{
|
|
147
|
+
if (rev) {
|
|
148
|
+
int i;
|
|
149
|
+
str_enlarge(s, l);
|
|
150
|
+
for (i = 0; i < l; ++i) {
|
|
151
|
+
int c = seq[l - 1 - i];
|
|
152
|
+
s->s[s->l + i] = c < 128 && comp? kom_comp_table[c] : c;
|
|
153
|
+
}
|
|
154
|
+
s->l += l;
|
|
155
|
+
} else str_copy(s, seq, seq + l);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
static inline const mb_hit_t *get_sam_pri(int n_hit, const mb_hit_t *hit)
|
|
159
|
+
{
|
|
160
|
+
int i;
|
|
161
|
+
for (i = 0; i < n_hit; ++i)
|
|
162
|
+
if (hit[i].sam_pri)
|
|
163
|
+
return &hit[i];
|
|
164
|
+
assert(n_hit == 0);
|
|
165
|
+
return NULL;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, const mb_hit_t *r, int64_t opt_flag)
|
|
169
|
+
{
|
|
170
|
+
if (r->p == 0) {
|
|
171
|
+
kom_sprintf_lite(s, "*");
|
|
172
|
+
} else {
|
|
173
|
+
uint32_t k, clip_len[2];
|
|
174
|
+
clip_len[0] = r->rev? qlen - r->qe : r->qs;
|
|
175
|
+
clip_len[1] = r->rev? r->qs : qlen - r->qe;
|
|
176
|
+
if (in_tag) {
|
|
177
|
+
int clip_char = (((sam_flag&0x800) || ((sam_flag&0x100) && (opt_flag&MB_F_2ND_SEQ))) &&
|
|
178
|
+
!(opt_flag&MB_F_SUPP_SOFT)) ? 5 : 4;
|
|
179
|
+
kom_sprintf_lite(s, "\tCG:B:I");
|
|
180
|
+
if (clip_len[0]) kom_sprintf_lite(s, ",%u", clip_len[0]<<4|clip_char);
|
|
181
|
+
for (k = 0; k < r->p->n_cigar; ++k)
|
|
182
|
+
kom_sprintf_lite(s, ",%u", r->p->cigar[k]);
|
|
183
|
+
if (clip_len[1]) kom_sprintf_lite(s, ",%u", clip_len[1]<<4|clip_char);
|
|
184
|
+
} else {
|
|
185
|
+
int clip_char = (((sam_flag&0x800) || ((sam_flag&0x100) && (opt_flag&MB_F_2ND_SEQ))) &&
|
|
186
|
+
!(opt_flag&MB_F_SUPP_SOFT)) ? 'H' : 'S';
|
|
187
|
+
assert(clip_len[0] < qlen && clip_len[1] < qlen);
|
|
188
|
+
if (clip_len[0]) kom_sprintf_lite(s, "%d%c", clip_len[0], clip_char);
|
|
189
|
+
for (k = 0; k < r->p->n_cigar; ++k)
|
|
190
|
+
kom_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, MB_CIGAR_STR[r->p->cigar[k]&0xf]);
|
|
191
|
+
if (clip_len[1]) kom_sprintf_lite(s, "%d%c", clip_len[1], clip_char);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
void mb_fmt_sam(void *km, kstring_t *s, const l2b_t *l2b, const mb_bseq1_t *t, int32_t n_seg, const int32_t *n_hit, mb_hit_t *const*hit, int32_t hit_idx, const mb_opt_t *opt, int seg_idx, int32_t mate_qlen)
|
|
197
|
+
{
|
|
198
|
+
int flag, n_h = n_hit[seg_idx];
|
|
199
|
+
int this_tid = -1, this_pos = -1;
|
|
200
|
+
const mb_hit_t *h = hit[seg_idx], *r_prev = NULL, *r_next;
|
|
201
|
+
const mb_hit_t *r = n_h > 0 && hit_idx < n_h && hit_idx >= 0? &h[hit_idx] : NULL;
|
|
202
|
+
|
|
203
|
+
assert(n_seg == 1 || n_seg == 2);
|
|
204
|
+
|
|
205
|
+
// find the primary of the previous and the next segments, if they are mapped
|
|
206
|
+
if (n_seg > 1) {
|
|
207
|
+
int next_sid = (seg_idx + 1) % n_seg;
|
|
208
|
+
r_prev = r_next = get_sam_pri(n_hit[next_sid], hit[next_sid]);
|
|
209
|
+
} else r_prev = r_next = NULL;
|
|
210
|
+
|
|
211
|
+
// write QNAME and FLAG
|
|
212
|
+
kom_sprintf_lite(s, "%s", t->name);
|
|
213
|
+
flag = n_seg > 1? 0x1 : 0x0;
|
|
214
|
+
if (r == 0) {
|
|
215
|
+
flag |= 0x4;
|
|
216
|
+
} else {
|
|
217
|
+
if (r->rev) flag |= 0x10;
|
|
218
|
+
if (r->parent != r->id) flag |= 0x100;
|
|
219
|
+
else if (!r->sam_pri) flag |= 0x800;
|
|
220
|
+
}
|
|
221
|
+
if (n_seg > 1) {
|
|
222
|
+
if (r && r->proper_pair) flag |= 0x2;
|
|
223
|
+
if (seg_idx == 0) flag |= 0x40;
|
|
224
|
+
else if (seg_idx == n_seg - 1) flag |= 0x80;
|
|
225
|
+
if (r_next == NULL) flag |= 0x8;
|
|
226
|
+
else if (r_next->rev) flag |= 0x20;
|
|
227
|
+
}
|
|
228
|
+
kom_sprintf_lite(s, "\t%d", flag);
|
|
229
|
+
|
|
230
|
+
// write coordinate, MAPQ and CIGAR
|
|
231
|
+
if (r == 0) {
|
|
232
|
+
if (r_prev) {
|
|
233
|
+
this_tid = r_prev->tid, this_pos = r_prev->ts;
|
|
234
|
+
kom_sprintf_lite(s, "\t%s\t%d\t0\t*", l2b->ctg[this_tid].name, this_pos+1);
|
|
235
|
+
} else kom_sprintf_lite(s, "\t*\t0\t0\t*");
|
|
236
|
+
} else {
|
|
237
|
+
this_tid = r->tid, this_pos = r->ts;
|
|
238
|
+
kom_sprintf_lite(s, "\t%s\t%d\t%d\t", l2b->ctg[r->tid].name, r->ts+1, r->mapq);
|
|
239
|
+
write_sam_cigar(s, flag, 0, t->l_seq, r, opt->flag);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// write mate positions
|
|
243
|
+
if (n_seg > 1) {
|
|
244
|
+
int tlen = 0;
|
|
245
|
+
if (this_tid >= 0 && r_next) {
|
|
246
|
+
if (this_tid == r_next->tid) {
|
|
247
|
+
if (r) {
|
|
248
|
+
int this_pos5 = r->rev? r->te - 1 : this_pos;
|
|
249
|
+
int next_pos5 = r_next->rev? r_next->te - 1 : r_next->ts;
|
|
250
|
+
tlen = next_pos5 - this_pos5;
|
|
251
|
+
}
|
|
252
|
+
kom_sprintf_lite(s, "\t=\t");
|
|
253
|
+
} else kom_sprintf_lite(s, "\t%s\t", l2b->ctg[r_next->tid].name);
|
|
254
|
+
kom_sprintf_lite(s, "%d\t", r_next->ts + 1);
|
|
255
|
+
} else if (r_next) { // && this_tid < 0
|
|
256
|
+
kom_sprintf_lite(s, "\t%s\t%d\t", l2b->ctg[r_next->tid].name, r_next->ts + 1);
|
|
257
|
+
} else if (this_tid >= 0) { // && r_next == NULL
|
|
258
|
+
kom_sprintf_lite(s, "\t=\t%d\t", this_pos + 1); // next segment will take r's coordinate
|
|
259
|
+
} else kom_sprintf_lite(s, "\t*\t0\t"); // neither has coordinates
|
|
260
|
+
if (tlen > 0) ++tlen;
|
|
261
|
+
else if (tlen < 0) --tlen;
|
|
262
|
+
kom_sprintf_lite(s, "%d\t", tlen);
|
|
263
|
+
} else kom_sprintf_lite(s, "\t*\t0\t0\t");
|
|
264
|
+
|
|
265
|
+
// write SEQ and QUAL
|
|
266
|
+
if (r == 0) {
|
|
267
|
+
sam_write_sq(s, t->seq, t->l_seq, 0, 0);
|
|
268
|
+
kom_sprintf_lite(s, "\t");
|
|
269
|
+
if (t->qual) sam_write_sq(s, t->qual, t->l_seq, 0, 0);
|
|
270
|
+
else kom_sprintf_lite(s, "*");
|
|
271
|
+
} else {
|
|
272
|
+
if ((flag & 0x900) == 0 || (opt->flag & MB_F_SUPP_SOFT)) {
|
|
273
|
+
sam_write_sq(s, t->seq, t->l_seq, r->rev, r->rev);
|
|
274
|
+
kom_sprintf_lite(s, "\t");
|
|
275
|
+
if (t->qual) sam_write_sq(s, t->qual, t->l_seq, r->rev, 0);
|
|
276
|
+
else kom_sprintf_lite(s, "*");
|
|
277
|
+
} else if ((flag & 0x100) && !(opt->flag & MB_F_2ND_SEQ)){
|
|
278
|
+
kom_sprintf_lite(s, "*\t*");
|
|
279
|
+
} else {
|
|
280
|
+
sam_write_sq(s, t->seq + r->qs, r->qe - r->qs, r->rev, r->rev);
|
|
281
|
+
kom_sprintf_lite(s, "\t");
|
|
282
|
+
if (t->qual) sam_write_sq(s, t->qual + r->qs, r->qe - r->qs, r->rev, 0);
|
|
283
|
+
else kom_sprintf_lite(s, "*");
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// write tags
|
|
288
|
+
if (mb_rg_id[0]) kom_sprintf_lite(s, "\tRG:Z:%s", mb_rg_id);
|
|
289
|
+
if (n_seg > 2) kom_sprintf_lite(s, "\tFI:i:%d", seg_idx);
|
|
290
|
+
if (r) {
|
|
291
|
+
write_tags(s, r);
|
|
292
|
+
// MC:Z mate CIGAR and MQ:i mate MAPQ; r_next is the mate's primary (see above).
|
|
293
|
+
if (n_seg > 1 && r_next && r_next->p && r_next->p->n_cigar > 0 && mate_qlen > 0) {
|
|
294
|
+
kom_sprintf_lite(s, "\tMC:Z:");
|
|
295
|
+
write_sam_cigar(s, 0, 0, mate_qlen, r_next, opt->flag);
|
|
296
|
+
kom_sprintf_lite(s, "\tMQ:i:%d", r_next->mapq);
|
|
297
|
+
}
|
|
298
|
+
if (r->p->cs) kom_sprintf_lite(s, "\t%s", (char*)&r->p->cigar[r->p->n_cigar]);
|
|
299
|
+
if (r->parent == r->id && r->p && n_h > 1 && h && r >= h && r - h < n_h) { // supplementary aln may exist
|
|
300
|
+
int i, n_sa = 0; // n_sa: number of SA fields
|
|
301
|
+
for (i = 0; i < n_h; ++i)
|
|
302
|
+
if (i != r - h && h[i].parent == h[i].id && h[i].p)
|
|
303
|
+
++n_sa;
|
|
304
|
+
if (n_sa > 0) {
|
|
305
|
+
kom_sprintf_lite(s, "\tSA:Z:");
|
|
306
|
+
for (i = 0; i < n_h; ++i) {
|
|
307
|
+
const mb_hit_t *q = &h[i];
|
|
308
|
+
int l_M, l_I = 0, l_D = 0, clip5 = 0, clip3 = 0;
|
|
309
|
+
if (r == q || q->parent != q->id || q->p == 0) continue;
|
|
310
|
+
if (q->qe - q->qs < q->te - q->ts) l_M = q->qe - q->qs, l_D = (q->te - q->ts) - l_M;
|
|
311
|
+
else l_M = q->te - q->ts, l_I = (q->qe - q->qs) - l_M;
|
|
312
|
+
clip5 = q->rev? t->l_seq - q->qe : q->qs;
|
|
313
|
+
clip3 = q->rev? q->qs : t->l_seq - q->qe;
|
|
314
|
+
kom_sprintf_lite(s, "%s,%d,%c,", l2b->ctg[q->tid].name, q->ts+1, "+-"[q->rev]);
|
|
315
|
+
if (clip5) kom_sprintf_lite(s, "%dS", clip5);
|
|
316
|
+
if (l_M) kom_sprintf_lite(s, "%dM", l_M);
|
|
317
|
+
if (l_I) kom_sprintf_lite(s, "%dI", l_I);
|
|
318
|
+
if (l_D) kom_sprintf_lite(s, "%dD", l_D);
|
|
319
|
+
if (clip3) kom_sprintf_lite(s, "%dS", clip3);
|
|
320
|
+
kom_sprintf_lite(s, ",%d,%d;", q->mapq, q->blen - q->mlen + q->p->n_ambi);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (opt->xa_max > 0) {
|
|
324
|
+
int i, n_xa = 0;
|
|
325
|
+
for (i = 0; i < n_h; ++i)
|
|
326
|
+
if (i != r - h && h[i].parent == r - h && h[i].p->dp_max >= (double)opt->out_s * r->p->dp_max)
|
|
327
|
+
++n_xa;
|
|
328
|
+
if (n_xa > 0) kom_sprintf_lite(s, "\tn2:i:%d", n_xa);
|
|
329
|
+
if (n_xa > 0 && n_xa <= opt->xa_max) {
|
|
330
|
+
kom_sprintf_lite(s, "\tXA:Z:");
|
|
331
|
+
for (i = 0; i < n_h; ++i) {
|
|
332
|
+
const mb_hit_t *q = &h[i];
|
|
333
|
+
if (i != r - h && q->parent == r - h && q->p->dp_max >= (double)opt->out_s * r->p->dp_max) {
|
|
334
|
+
kom_sprintf_lite(s, "%s,%c%d,", l2b->ctg[q->tid].name, "+-"[q->rev], q->ts+1);
|
|
335
|
+
write_sam_cigar(s, 0, 0, t->l_seq, q, opt->flag);
|
|
336
|
+
kom_sprintf_lite(s, ",%d;", q->blen - q->mlen + q->p->n_ambi);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if ((opt->flag & MB_F_COPY_COMMENT) && t->comment)
|
|
345
|
+
kom_sprintf_lite(s, "\t%s", t->comment);
|
|
346
|
+
kom_sprintf_lite(s, "\n");
|
|
347
|
+
s->s[s->l] = 0; // we always have room for an extra byte
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
void mb_format(void *km, kstring_t *s, const l2b_t *l2b, const mb_bseq1_t *t, int32_t n_seg, const int32_t *n_hit, mb_hit_t *const*hit, int32_t hit_idx, const mb_opt_t *opt, int seg_idx, int32_t mate_qlen)
|
|
351
|
+
{
|
|
352
|
+
if (!(opt->flag & MB_F_PAF))
|
|
353
|
+
mb_fmt_sam(km, s, l2b, t, n_seg, n_hit, hit, hit_idx, opt, seg_idx, mate_qlen);
|
|
354
|
+
else
|
|
355
|
+
mb_fmt_paf(s, l2b, t, hit_idx >= 0? &hit[seg_idx][hit_idx] : 0, opt->flag, n_seg, seg_idx);
|
|
356
|
+
}
|