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,769 @@
|
|
|
1
|
+
#include <stdlib.h>
|
|
2
|
+
#include <stdio.h>
|
|
3
|
+
#include <math.h>
|
|
4
|
+
#include "mbpriv.h"
|
|
5
|
+
#include "kalloc.h"
|
|
6
|
+
#include "kommon.h"
|
|
7
|
+
#include "ksort.h"
|
|
8
|
+
|
|
9
|
+
#define key_128x(a) ((a).x)
|
|
10
|
+
KRADIX_SORT_INIT(mb128x, mb128_t, key_128x, 8)
|
|
11
|
+
|
|
12
|
+
#define key_64(a) (a)
|
|
13
|
+
KRADIX_SORT_INIT(mb64, uint64_t, key_64, 8)
|
|
14
|
+
|
|
15
|
+
/*****************
|
|
16
|
+
* Index loading *
|
|
17
|
+
*****************/
|
|
18
|
+
|
|
19
|
+
mb_idx_t *mb_idx_load(const char *prefix, int32_t is_meth)
|
|
20
|
+
{
|
|
21
|
+
char *buf;
|
|
22
|
+
mb_idx_t *idx = 0;
|
|
23
|
+
l2b_t *l2b;
|
|
24
|
+
mb_bwt_t *bwt;
|
|
25
|
+
buf = kom_calloc(char, strlen(prefix) + 10);
|
|
26
|
+
strcat(strcpy(buf, prefix), ".l2b");
|
|
27
|
+
l2b = l2b_load(buf);
|
|
28
|
+
if (l2b == 0) goto end_idx_load;
|
|
29
|
+
if (is_meth) strcat(strcpy(buf, prefix), ".meth.mbw");
|
|
30
|
+
else strcat(strcpy(buf, prefix), ".mbw");
|
|
31
|
+
bwt = mb_bwt_load(buf);
|
|
32
|
+
if (bwt == 0) {
|
|
33
|
+
l2b_destroy(l2b);
|
|
34
|
+
goto end_idx_load;
|
|
35
|
+
}
|
|
36
|
+
mb_bwt_cache(bwt, 10); // TODO: don't hard code this
|
|
37
|
+
idx = kom_calloc(mb_idx_t, 1);
|
|
38
|
+
idx->is_meth = !!is_meth, idx->l2b = l2b, idx->bwt = bwt;
|
|
39
|
+
end_idx_load:
|
|
40
|
+
free(buf);
|
|
41
|
+
return idx;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
mb_idx_t *mb_idx_load_mmap(const char *prefix, int32_t is_meth, int preload)
|
|
45
|
+
{
|
|
46
|
+
char *buf;
|
|
47
|
+
mb_idx_t *idx = 0;
|
|
48
|
+
l2b_t *l2b;
|
|
49
|
+
mb_bwt_t *bwt;
|
|
50
|
+
buf = kom_calloc(char, strlen(prefix) + 10);
|
|
51
|
+
strcat(strcpy(buf, prefix), ".l2b");
|
|
52
|
+
l2b = l2b_load_mmap(buf, preload);
|
|
53
|
+
if (l2b == 0) goto end_idx_load_mmap;
|
|
54
|
+
if (is_meth) strcat(strcpy(buf, prefix), ".meth.mbw");
|
|
55
|
+
else strcat(strcpy(buf, prefix), ".mbw");
|
|
56
|
+
bwt = mb_bwt_load_mmap(buf, preload);
|
|
57
|
+
if (bwt == 0) {
|
|
58
|
+
l2b_destroy(l2b);
|
|
59
|
+
goto end_idx_load_mmap;
|
|
60
|
+
}
|
|
61
|
+
mb_bwt_cache(bwt, 10); // TODO: don't hard code this
|
|
62
|
+
idx = kom_calloc(mb_idx_t, 1);
|
|
63
|
+
idx->is_meth = !!is_meth, idx->l2b = l2b, idx->bwt = bwt;
|
|
64
|
+
end_idx_load_mmap:
|
|
65
|
+
free(buf);
|
|
66
|
+
return idx;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
void mb_idx_destroy(mb_idx_t *idx)
|
|
70
|
+
{
|
|
71
|
+
if (idx == 0) return;
|
|
72
|
+
mb_bwt_destroy(idx->bwt);
|
|
73
|
+
l2b_destroy(idx->l2b);
|
|
74
|
+
free(idx);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const char *mb_idx_ctg_name(const mb_idx_t *idx, int32_t tid)
|
|
78
|
+
{
|
|
79
|
+
return tid >= 0 && tid < idx->l2b->n_ctg? idx->l2b->ctg[tid].name : 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
int64_t mb_idx_ctg_len(const mb_idx_t *idx, int32_t tid)
|
|
83
|
+
{
|
|
84
|
+
return tid >= 0 && tid < idx->l2b->n_ctg? idx->l2b->ctg[tid].len : -1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*****************
|
|
88
|
+
* Thread buffer *
|
|
89
|
+
*****************/
|
|
90
|
+
|
|
91
|
+
struct mb_tbuf_s {
|
|
92
|
+
void *km;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
mb_tbuf_t *mb_tbuf_init(int no_kalloc)
|
|
96
|
+
{
|
|
97
|
+
mb_tbuf_t *b;
|
|
98
|
+
b = kom_calloc(mb_tbuf_t, 1);
|
|
99
|
+
if (!no_kalloc) b->km = km_init();
|
|
100
|
+
return b;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void *mb_tbuf_km(mb_tbuf_t *b)
|
|
104
|
+
{
|
|
105
|
+
return b->km;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void mb_tbuf_destroy(mb_tbuf_t *b)
|
|
109
|
+
{
|
|
110
|
+
if (b->km) km_destroy(b->km);
|
|
111
|
+
free(b);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
int32_t mb_tbuf_reset(mb_tbuf_t *b, int64_t max_blk_sz)
|
|
115
|
+
{
|
|
116
|
+
km_stat_t kmst;
|
|
117
|
+
int64_t max_sz = max_blk_sz < 1U<<28? max_blk_sz : 1U<<28;
|
|
118
|
+
if (b->km == 0) return 0;
|
|
119
|
+
km_stat(b->km, &kmst);
|
|
120
|
+
assert(kmst.n_blocks == kmst.n_cores);
|
|
121
|
+
if (kmst.largest > max_sz || kmst.capacity > max_sz * 2) {
|
|
122
|
+
km_destroy(b->km);
|
|
123
|
+
b->km = km_init();
|
|
124
|
+
return 1;
|
|
125
|
+
}
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/************************
|
|
130
|
+
* Basic hit operations *
|
|
131
|
+
************************/
|
|
132
|
+
|
|
133
|
+
int32_t mb_cal_mblen(int32_t n, const mb_anchor_t *a, int32_t *blen_)
|
|
134
|
+
{
|
|
135
|
+
int32_t i;
|
|
136
|
+
int64_t mlen, blen;
|
|
137
|
+
*blen_ = 0;
|
|
138
|
+
if (n <= 0) return 0;
|
|
139
|
+
mlen = blen = a[0].len;
|
|
140
|
+
for (i = 1; i < n; ++i) {
|
|
141
|
+
int span = a[i].len;
|
|
142
|
+
int tl = (int32_t)a[i].tpos - (int32_t)a[i-1].tpos;
|
|
143
|
+
int ql = (int32_t)a[i].qpos - (int32_t)a[i-1].qpos;
|
|
144
|
+
blen += tl > ql? tl : ql;
|
|
145
|
+
mlen += tl > span && ql > span? span : tl < ql? tl : ql;
|
|
146
|
+
}
|
|
147
|
+
*blen_ = blen;
|
|
148
|
+
return mlen;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static void mb_cal_fuzzy_len(mb_hit_t *r, const mb_anchor_t *a)
|
|
152
|
+
{
|
|
153
|
+
r->mlen = mb_cal_mblen(r->cnt, &a[r->as], &r->blen);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static inline void mb_hit_set_coor(mb_hit_t *r, int32_t qlen, const l2b_t *l2b, const mb_anchor_t *a)
|
|
157
|
+
{ // NB: r->as and r->cnt MUST BE set correctly for this function to work
|
|
158
|
+
int32_t k = r->as;
|
|
159
|
+
const mb_anchor_t *ak0 = &a[k];
|
|
160
|
+
const mb_anchor_t *ak1 = &a[k + r->cnt - 1];
|
|
161
|
+
|
|
162
|
+
r->tid = ak0->sid>>1, r->rev = ak0->sid&1;
|
|
163
|
+
r->ts = ak0->tpos + 1 - ak0->len;
|
|
164
|
+
r->te = ak1->tpos + 1;
|
|
165
|
+
if (!r->rev) { // forward strand
|
|
166
|
+
r->qs = ak0->qpos + 1 - ak0->len;
|
|
167
|
+
r->qe = ak1->qpos + 1;
|
|
168
|
+
} else { // reverse strand
|
|
169
|
+
r->qs = qlen - (ak1->qpos + 1);
|
|
170
|
+
r->qe = qlen - (ak0->qpos + 1 - ak0->len);
|
|
171
|
+
}
|
|
172
|
+
mb_cal_fuzzy_len(r, a);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
int32_t mb_cal_high_cov(void *km, int32_t n, const mb_sai_t *sai, int32_t max_occ)
|
|
176
|
+
{
|
|
177
|
+
int32_t i, n_hi = 0, hi_st, hi_en, hi_cov;
|
|
178
|
+
uint64_t *b;
|
|
179
|
+
for (i = 0; i < n; ++i)
|
|
180
|
+
if (sai[i].size > max_occ)
|
|
181
|
+
++n_hi;
|
|
182
|
+
if (n_hi == 0) return 0;
|
|
183
|
+
b = Kmalloc(km, uint64_t, n_hi);
|
|
184
|
+
for (i = 0, n_hi = 0; i < n; ++i)
|
|
185
|
+
if (sai[i].size > max_occ)
|
|
186
|
+
b[n_hi++] = sai[i].info;
|
|
187
|
+
radix_sort_mb64(b, b + n_hi);
|
|
188
|
+
hi_st = b[0]>>32, hi_en = (int32_t)b[0], hi_cov = 0;
|
|
189
|
+
for (i = 1; i < n_hi; ++i) {
|
|
190
|
+
int32_t st = b[i]>>32, en = (int32_t)b[i];
|
|
191
|
+
if (st > hi_en) {
|
|
192
|
+
hi_cov += hi_en - hi_st;
|
|
193
|
+
hi_st = st, hi_en = en;
|
|
194
|
+
} else hi_en = hi_en > en? hi_en : en;
|
|
195
|
+
}
|
|
196
|
+
hi_cov += hi_en - hi_st;
|
|
197
|
+
kfree(km, b);
|
|
198
|
+
return hi_cov;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void mb_sync_high_cov(int32_t n, mb_hit_t *h)
|
|
202
|
+
{
|
|
203
|
+
int32_t i, max_frac = 0;
|
|
204
|
+
for (i = 0; i < n; ++i)
|
|
205
|
+
max_frac = max_frac > h[i].frac_high? max_frac : h[i].frac_high;
|
|
206
|
+
for (i = 0; i < n; ++i)
|
|
207
|
+
h[i].frac_high = max_frac;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
mb_hit_t *mb_gen_hit(void *km, uint32_t hash, int qlen, const l2b_t *l2b, int n_u, uint64_t *u, mb_anchor_t *a)
|
|
211
|
+
{ // convert chains to hits
|
|
212
|
+
mb128_t *z, tmp;
|
|
213
|
+
mb_hit_t *r;
|
|
214
|
+
int i, k;
|
|
215
|
+
|
|
216
|
+
if (n_u <= 0) return 0;
|
|
217
|
+
|
|
218
|
+
// sort by score
|
|
219
|
+
z = Kmalloc(km, mb128_t, n_u);
|
|
220
|
+
for (i = k = 0; i < n_u; ++i) {
|
|
221
|
+
uint32_t h;
|
|
222
|
+
h = (uint32_t)mb_hash64((mb_hash64(a[k].tpos) + mb_hash64(a[k].qpos)) ^ hash);
|
|
223
|
+
z[i].x = u[i] ^ h; // u[i] -- higher 32 bits: chain score; lower 32 bits: number of anchors
|
|
224
|
+
z[i].y = (uint64_t)k << 32 | (int32_t)u[i];
|
|
225
|
+
k += (int32_t)u[i];
|
|
226
|
+
}
|
|
227
|
+
radix_sort_mb128x(z, z + n_u);
|
|
228
|
+
for (i = 0; i < n_u>>1; ++i) // reverse, s.t. larger score first
|
|
229
|
+
tmp = z[i], z[i] = z[n_u-1-i], z[n_u-1-i] = tmp;
|
|
230
|
+
|
|
231
|
+
// populate r[]
|
|
232
|
+
r = (mb_hit_t*)calloc(n_u, sizeof(mb_hit_t));
|
|
233
|
+
for (i = 0; i < n_u; ++i) {
|
|
234
|
+
mb_hit_t *ri = &r[i];
|
|
235
|
+
ri->id = i;
|
|
236
|
+
ri->parent = MB_PARENT_UNSET;
|
|
237
|
+
ri->score = ri->score0 = z[i].x >> 32;
|
|
238
|
+
ri->hash = (uint32_t)z[i].x;
|
|
239
|
+
ri->cnt = (int32_t)z[i].y;
|
|
240
|
+
ri->as = z[i].y >> 32;
|
|
241
|
+
mb_hit_set_coor(ri, qlen, l2b, a);
|
|
242
|
+
}
|
|
243
|
+
kfree(km, z);
|
|
244
|
+
return r;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
void mb_split_hit(mb_hit_t *r, mb_hit_t *r2, int n, int qlen, mb_anchor_t *a, const l2b_t *l2b)
|
|
248
|
+
{
|
|
249
|
+
if (n <= 0 || n >= r->cnt) return;
|
|
250
|
+
*r2 = *r;
|
|
251
|
+
r2->id = -1;
|
|
252
|
+
r2->sam_pri = 0;
|
|
253
|
+
r2->p = 0;
|
|
254
|
+
r2->split_inv = 0;
|
|
255
|
+
r2->cnt = r->cnt - n;
|
|
256
|
+
r2->score = (int32_t)(r->score * ((float)r2->cnt / r->cnt) + .499);
|
|
257
|
+
r2->as = r->as + n;
|
|
258
|
+
if (r->parent == r->id) r2->parent = MB_PARENT_TMP_PRI;
|
|
259
|
+
mb_hit_set_coor(r2, qlen, l2b, a);
|
|
260
|
+
r->cnt -= r2->cnt;
|
|
261
|
+
r->score -= r2->score;
|
|
262
|
+
mb_hit_set_coor(r, qlen, l2b, a);
|
|
263
|
+
r->split |= 1, r2->split |= 2;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
void mb_sync_hits(void *km, int n_regs, mb_hit_t *regs)
|
|
267
|
+
{
|
|
268
|
+
int *tmp, i, max_id = -1, n_tmp;
|
|
269
|
+
if (n_regs <= 0) return;
|
|
270
|
+
for (i = 0; i < n_regs; ++i)
|
|
271
|
+
max_id = max_id > regs[i].id? max_id : regs[i].id;
|
|
272
|
+
n_tmp = max_id + 1;
|
|
273
|
+
tmp = (int*)kmalloc(km, n_tmp * sizeof(int));
|
|
274
|
+
for (i = 0; i < n_tmp; ++i) tmp[i] = -1;
|
|
275
|
+
for (i = 0; i < n_regs; ++i)
|
|
276
|
+
if (regs[i].id >= 0) tmp[regs[i].id] = i;
|
|
277
|
+
for (i = 0; i < n_regs; ++i) {
|
|
278
|
+
mb_hit_t *r = ®s[i];
|
|
279
|
+
r->id = i;
|
|
280
|
+
if (r->parent == MB_PARENT_TMP_PRI)
|
|
281
|
+
r->parent = i;
|
|
282
|
+
else if (r->parent >= 0 && tmp[r->parent] >= 0)
|
|
283
|
+
r->parent = tmp[r->parent];
|
|
284
|
+
else r->parent = MB_PARENT_UNSET;
|
|
285
|
+
}
|
|
286
|
+
kfree(km, tmp);
|
|
287
|
+
mb_set_sam_pri(n_regs, regs, 0); // this flag will be overwritten later anyway
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**********************************
|
|
291
|
+
* Set primary and secondary hits *
|
|
292
|
+
**********************************/
|
|
293
|
+
|
|
294
|
+
static int update_sub(mb_hit_t *ri, mb_hit_t *rp, float mask_level, int mask_len, int sub_diff, int uncov_len)
|
|
295
|
+
{
|
|
296
|
+
int si = ri->qs, ei = ri->qe, sj = rp->qs, ej = rp->qe, min, max, ol;
|
|
297
|
+
if (ej <= si || sj >= ei) return 0;
|
|
298
|
+
min = ej - sj < ei - si? ej - sj : ei - si;
|
|
299
|
+
max = ej - sj > ei - si? ej - sj : ei - si;
|
|
300
|
+
ol = ej <= si || sj >= ei? 0 : (ej < ei? ej : ei) - (sj > si? sj : si);
|
|
301
|
+
if ((double)ol / min - (double)uncov_len / max > mask_level && uncov_len <= mask_len) {
|
|
302
|
+
int cnt_sub = 0, sci = ri->score;
|
|
303
|
+
ri->parent = rp->parent;
|
|
304
|
+
rp->subsc = rp->subsc > sci? rp->subsc : sci;
|
|
305
|
+
if (rp->p && ri->p && (rp->tid != ri->tid || rp->ts != ri->ts || rp->te != ri->te || ol != min)) { // the last condition excludes identical hits after DP
|
|
306
|
+
sci = ri->p->dp_max;
|
|
307
|
+
rp->p->dp_max2 = rp->p->dp_max2 > sci? rp->p->dp_max2 : sci;
|
|
308
|
+
if (rp->p->dp_max - ri->p->dp_max <= sub_diff) cnt_sub = 1;
|
|
309
|
+
}
|
|
310
|
+
if (cnt_sub) ++rp->n_sub;
|
|
311
|
+
return 1;
|
|
312
|
+
} else return 0;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
void mb_set_parent(void *km, float mask_level, int mask_len, int n, mb_hit_t *r, int sub_diff, int hard_mask_level)
|
|
316
|
+
{ // TODO: re-examine the logic for variable-length seeds
|
|
317
|
+
int i, j, k, *w;
|
|
318
|
+
uint64_t *cov;
|
|
319
|
+
if (n <= 0) return;
|
|
320
|
+
for (i = 0; i < n; ++i) r[i].id = i;
|
|
321
|
+
cov = Kmalloc(km, uint64_t, n);
|
|
322
|
+
w = Kmalloc(km, int, n);
|
|
323
|
+
w[0] = 0, r[0].parent = 0;
|
|
324
|
+
for (i = 1, k = 1; i < n; ++i) {
|
|
325
|
+
mb_hit_t *ri = &r[i];
|
|
326
|
+
int si = ri->qs, ei = ri->qe, n_cov = 0, uncov_len = 0, max_ol, max_j, n_par = 0;
|
|
327
|
+
if (hard_mask_level) goto skip_uncov;
|
|
328
|
+
for (j = 0; j < k; ++j) {
|
|
329
|
+
const mb_hit_t *rp = &r[w[j]];
|
|
330
|
+
int sj = rp->qs, ej = rp->qe;
|
|
331
|
+
if (ej <= si || sj >= ei) continue;
|
|
332
|
+
if (sj < si) sj = si;
|
|
333
|
+
if (ej > ei) ej = ei;
|
|
334
|
+
cov[n_cov++] = (uint64_t)sj<<32 | ej;
|
|
335
|
+
}
|
|
336
|
+
if (n_cov == 0) {
|
|
337
|
+
goto add_primary;
|
|
338
|
+
} else {
|
|
339
|
+
int j, x = si;
|
|
340
|
+
radix_sort_mb64(cov, cov + n_cov);
|
|
341
|
+
for (j = 0; j < n_cov; ++j) {
|
|
342
|
+
if ((int)(cov[j]>>32) > x) uncov_len += (cov[j]>>32) - x;
|
|
343
|
+
x = (int32_t)cov[j] > x? (int32_t)cov[j] : x;
|
|
344
|
+
}
|
|
345
|
+
if (ei > x) uncov_len += ei - x;
|
|
346
|
+
}
|
|
347
|
+
skip_uncov:
|
|
348
|
+
for (j = 0, max_ol = 0, max_j = -1; j < k; ++j) { // find the parent with the maximum overlap
|
|
349
|
+
const mb_hit_t *rp = &r[w[j]];
|
|
350
|
+
int sj = rp->qs, ej = rp->qe;
|
|
351
|
+
int ol = ej <= si || sj >= ei? 0 : (ej < ei? ej : ei) - (sj > si? sj : si);
|
|
352
|
+
if (max_ol < ol) max_ol = ol, max_j = j;
|
|
353
|
+
}
|
|
354
|
+
if (max_j >= 0) {
|
|
355
|
+
n_par += update_sub(ri, &r[w[max_j]], mask_level, mask_len, sub_diff, uncov_len);
|
|
356
|
+
for (j = 0; j < k && n_par == 0; ++j) // if no parent found on the longest overlap, try more
|
|
357
|
+
n_par += update_sub(ri, &r[w[j]], mask_level, mask_len, sub_diff, uncov_len);
|
|
358
|
+
}
|
|
359
|
+
add_primary:
|
|
360
|
+
if (n_par == 0) w[k++] = i, ri->parent = i, ri->n_sub = 0;
|
|
361
|
+
}
|
|
362
|
+
kfree(km, cov);
|
|
363
|
+
kfree(km, w);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
void mb_set_sam_pri(int32_t n, mb_hit_t *r, int32_t is_primary5)
|
|
367
|
+
{
|
|
368
|
+
int32_t i, n_pri = 0, min_i = -1, min_qs = -1, first_i = -1;
|
|
369
|
+
if (n <= 0) return;
|
|
370
|
+
for (i = 0; i < n; ++i) {
|
|
371
|
+
r[i].sam_pri = 0;
|
|
372
|
+
if (r[i].id != r[i].parent) continue;
|
|
373
|
+
if (++n_pri == 1) first_i = i;
|
|
374
|
+
if (min_qs < 0 || r[i].qs < min_qs)
|
|
375
|
+
min_i = i, min_qs = r[i].qs;
|
|
376
|
+
}
|
|
377
|
+
assert(n_pri > 0);
|
|
378
|
+
if (is_primary5) r[min_i].sam_pri = 1;
|
|
379
|
+
else r[first_i].sam_pri = 1;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
void mb_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_, mb_hit_t *r)
|
|
383
|
+
{
|
|
384
|
+
if (pri_ratio > 0.0f && *n_ > 0) {
|
|
385
|
+
int i, k, n = *n_, n_2nd = 0;
|
|
386
|
+
uint8_t *keep = Kcalloc(km, uint8_t, n);
|
|
387
|
+
for (i = 0; i < n; ++i) {
|
|
388
|
+
int p = r[i].parent;
|
|
389
|
+
if (p == i || r[i].inv) {
|
|
390
|
+
keep[i] = 1;
|
|
391
|
+
} else if ((r[i].score >= r[p].score * pri_ratio || r[i].score + min_diff >= r[p].score) && n_2nd < best_n) {
|
|
392
|
+
if (!(r[i].qs == r[p].qs && r[i].qe == r[p].qe && r[i].tid == r[p].tid && r[i].ts == r[p].ts && r[i].te == r[p].te))
|
|
393
|
+
keep[i] = 1, ++n_2nd;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
for (i = k = 0; i < n; ++i) {
|
|
397
|
+
if (keep[i]) r[k++] = r[i];
|
|
398
|
+
else if (r[i].p) free(r[i].p); // r->p is libc-allocated; free here before the pointer is lost
|
|
399
|
+
}
|
|
400
|
+
kfree(km, keep);
|
|
401
|
+
if (k != n) mb_sync_hits(km, k, r);
|
|
402
|
+
*n_ = k;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
void mb_hit_sort(void *km, int *n_regs, mb_hit_t *r)
|
|
407
|
+
{
|
|
408
|
+
int32_t i, n_aux, n = *n_regs;
|
|
409
|
+
mb128_t *aux;
|
|
410
|
+
mb_hit_t *t;
|
|
411
|
+
|
|
412
|
+
if (n <= 1) return;
|
|
413
|
+
aux = (mb128_t*)kmalloc(km, (size_t)n * 16);
|
|
414
|
+
t = (mb_hit_t*)kmalloc(km, (size_t)n * sizeof(mb_hit_t));
|
|
415
|
+
for (i = n_aux = 0; i < n; ++i) {
|
|
416
|
+
if (r[i].inv || r[i].cnt >= 0) {
|
|
417
|
+
int score = r[i].p? r[i].p->dp_max : r[i].score;
|
|
418
|
+
aux[n_aux].x = (uint64_t)score << 32 | r[i].hash;
|
|
419
|
+
aux[n_aux++].y = i;
|
|
420
|
+
} else if (r[i].p) {
|
|
421
|
+
free(r[i].p);
|
|
422
|
+
r[i].p = 0;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
radix_sort_mb128x(aux, aux + n_aux);
|
|
426
|
+
for (i = n_aux - 1; i >= 0; --i)
|
|
427
|
+
t[n_aux - 1 - i] = r[aux[i].y];
|
|
428
|
+
memcpy(r, t, sizeof(mb_hit_t) * n_aux);
|
|
429
|
+
*n_regs = n_aux;
|
|
430
|
+
kfree(km, aux);
|
|
431
|
+
kfree(km, t);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
void mb_filter_hits(const mb_opt_t *opt, int qlen, int *n_regs, mb_hit_t *regs)
|
|
435
|
+
{
|
|
436
|
+
int i, k;
|
|
437
|
+
for (i = k = 0; i < *n_regs; ++i) {
|
|
438
|
+
mb_hit_t *r = ®s[i];
|
|
439
|
+
int flt = r->flt;
|
|
440
|
+
if (r->p) {
|
|
441
|
+
if (r->mlen < opt->min_chain_score) flt = 1;
|
|
442
|
+
else if (r->p->dp_max < opt->min_dp_max * opt->a) flt = 1;
|
|
443
|
+
if (flt) free(r->p);
|
|
444
|
+
}
|
|
445
|
+
if (!flt) {
|
|
446
|
+
if (k < i) regs[k++] = regs[i];
|
|
447
|
+
else ++k;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
*n_regs = k;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
int mb_squeeze_a(void *km, int n_regs, mb_hit_t *regs, mb_anchor_t *a)
|
|
454
|
+
{
|
|
455
|
+
int i, as = 0;
|
|
456
|
+
uint64_t *aux;
|
|
457
|
+
aux = (uint64_t*)kmalloc(km, (size_t)n_regs * 8);
|
|
458
|
+
for (i = 0; i < n_regs; ++i)
|
|
459
|
+
aux[i] = (uint64_t)regs[i].as << 32 | i;
|
|
460
|
+
radix_sort_mb64(aux, aux + n_regs);
|
|
461
|
+
for (i = 0; i < n_regs; ++i) {
|
|
462
|
+
mb_hit_t *r = ®s[(int32_t)aux[i]];
|
|
463
|
+
if (r->as != as) {
|
|
464
|
+
memmove(&a[as], &a[r->as], (size_t)r->cnt * sizeof(mb_anchor_t));
|
|
465
|
+
r->as = as;
|
|
466
|
+
}
|
|
467
|
+
as += r->cnt;
|
|
468
|
+
}
|
|
469
|
+
kfree(km, aux);
|
|
470
|
+
return as;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/*******************
|
|
474
|
+
* Mapping quality *
|
|
475
|
+
*******************/
|
|
476
|
+
|
|
477
|
+
static void mb_set_inv_mapq(void *km, int n_regs, mb_hit_t *regs)
|
|
478
|
+
{
|
|
479
|
+
int i, n_aux;
|
|
480
|
+
mb128_t *aux;
|
|
481
|
+
if (n_regs < 3) return;
|
|
482
|
+
for (i = 0; i < n_regs; ++i)
|
|
483
|
+
if (regs[i].inv) break;
|
|
484
|
+
if (i == n_regs) return; // no inversion hits
|
|
485
|
+
|
|
486
|
+
aux = Kmalloc(km, mb128_t, n_regs);
|
|
487
|
+
for (i = n_aux = 0; i < n_regs; ++i)
|
|
488
|
+
if (regs[i].parent == i || regs[i].parent < 0)
|
|
489
|
+
aux[n_aux].y = i, aux[n_aux++].x = (uint64_t)regs[i].tid << 32 | regs[i].ts;
|
|
490
|
+
radix_sort_mb128x(aux, aux + n_aux);
|
|
491
|
+
|
|
492
|
+
for (i = 1; i < n_aux - 1; ++i) {
|
|
493
|
+
mb_hit_t *inv = ®s[aux[i].y];
|
|
494
|
+
if (inv->inv) {
|
|
495
|
+
mb_hit_t *l = ®s[aux[i-1].y];
|
|
496
|
+
mb_hit_t *r = ®s[aux[i+1].y];
|
|
497
|
+
inv->mapq = l->mapq < r->mapq? l->mapq : r->mapq;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
kfree(km, aux);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
void mb_set_mapq(void *km, int32_t qlen, int n_regs, mb_hit_t *regs, int min_chain_sc, int match_sc, int is_sr, int max_sr_len)
|
|
504
|
+
{
|
|
505
|
+
const int32_t mapQ_coef_len = 50;
|
|
506
|
+
const double mapQ_coef_fac = 3.0; // should be log(mapQ_coef_len)), but bwa-mem uses 3.0 due to a bug. Let's match bwa-mem
|
|
507
|
+
const double q_coef = 40.0f;
|
|
508
|
+
int i;
|
|
509
|
+
if (n_regs == 0) return;
|
|
510
|
+
for (i = 0; i < n_regs; ++i) {
|
|
511
|
+
mb_hit_t *r = ®s[i];
|
|
512
|
+
if (r->inv) {
|
|
513
|
+
r->mapq = 0;
|
|
514
|
+
} else if (r->parent == r->id) {
|
|
515
|
+
int mapq, mapq_sr, mapq_lr, subsc;
|
|
516
|
+
double pen_chn = r->score > qlen * 0.1? 1.0 : 10.0 * r->score / qlen; // penalize chains with few matching bases
|
|
517
|
+
subsc = r->subsc > min_chain_sc? r->subsc : min_chain_sc;
|
|
518
|
+
if (r->p && r->p->dp_max2 > 0 && r->p->dp_max > 0) {
|
|
519
|
+
double x, identity = (double)r->mlen / r->blen;
|
|
520
|
+
// BWA-MEM formula for short reads
|
|
521
|
+
x = r->blen < mapQ_coef_len? 1. : mapQ_coef_fac / log(r->blen);
|
|
522
|
+
x *= identity * identity;
|
|
523
|
+
mapq_sr = (int)(6.02 * x * x * (r->p->dp_max - r->p->dp_max2) / match_sc + .499f);
|
|
524
|
+
// minimap2 formula for long reads
|
|
525
|
+
x = (double)r->p->dp_max2 / r->p->dp_max;
|
|
526
|
+
if (subsc > r->score0) x *= (double)subsc / r->score0;
|
|
527
|
+
mapq_lr = (int)(pen_chn * identity * q_coef * (1.0 - x * x) * log((double)r->p->dp_max / match_sc));
|
|
528
|
+
// final mapq
|
|
529
|
+
if (is_sr) mapq = mapq_sr;
|
|
530
|
+
else if (max_sr_len < 0) mapq = mapq_lr;
|
|
531
|
+
else mapq = qlen < max_sr_len? mapq_sr : (int32_t)(mapq_lr - (mapq_lr - mapq_sr) * pow(2.0, 1.0 - (double)qlen / max_sr_len) + .499);
|
|
532
|
+
} else { // minimap2 formula
|
|
533
|
+
double x = (double)subsc / r->score0;
|
|
534
|
+
if (r->p) {
|
|
535
|
+
double identity = (double)r->mlen / r->blen;
|
|
536
|
+
mapq = (int)(pen_chn * identity * q_coef * (1.0f - x) * log((double)r->p->dp_max / match_sc));
|
|
537
|
+
} else {
|
|
538
|
+
mapq = (int)(pen_chn * q_coef * (1.0f - x) * log(r->score));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
mapq -= (int)(4.343f * log(r->n_sub + 1) + .499f);
|
|
542
|
+
mapq = mapq > 0? mapq : 0;
|
|
543
|
+
if (r->seed_ratio < 50) mapq *= (double)r->seed_ratio * r->seed_ratio / 2500.0;
|
|
544
|
+
r->mapq = mapq < 60? mapq : 60;
|
|
545
|
+
if (r->p && r->p->dp_max > r->p->dp_max2 && r->mapq == 0) r->mapq = 1;
|
|
546
|
+
} else r->mapq = 0;
|
|
547
|
+
}
|
|
548
|
+
mb_set_inv_mapq(km, n_regs, regs);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/************************
|
|
552
|
+
* Core mapping routine *
|
|
553
|
+
************************/
|
|
554
|
+
|
|
555
|
+
static void mb_dbg_seed(int64_t n, const mb_sai_t *u, const char *qname)
|
|
556
|
+
{
|
|
557
|
+
int64_t i;
|
|
558
|
+
for (i = 0; i < n; ++i) {
|
|
559
|
+
const mb_sai_t *p = &u[i];
|
|
560
|
+
fprintf(stderr, "SD\t%s\t%d\t%d\t%ld\n", qname? qname : "*", (int32_t)(p->info>>32), (int32_t)p->info, (long)p->size);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
static void mb_dbg_anchor(const mb_idx_t *idx, int qlen, int64_t n, const mb_anchor_t *a, const char *qname)
|
|
565
|
+
{
|
|
566
|
+
int64_t i;
|
|
567
|
+
for (i = 0; i < n; ++i) {
|
|
568
|
+
const mb_anchor_t *ai = &a[i];
|
|
569
|
+
int rid = ai->sid >> 1;
|
|
570
|
+
int rev = ai->sid & 1;
|
|
571
|
+
int32_t qs = rev? qlen - 1 - ai->qpos : ai->qpos + 1 - ai->len;
|
|
572
|
+
int64_t ts = ai->tpos + 1 - ai->len;
|
|
573
|
+
fprintf(stderr, "AC\t%s\t%d\t%c\t%s\t%ld\t%d\n", qname? qname : "*", qs, "+-"[rev], idx->l2b->ctg[rid].name, (long)ts, ai->len);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
mb_hit_t *mb_map_sai(const mb_opt_t *opt, const mb_idx_t *idx, int64_t qlen, const char *seq0, l2b_meth_t mt, mb_sai_v *u, int32_t *n_hit_, mb_tbuf_t *b, const char *qname)
|
|
578
|
+
{
|
|
579
|
+
const int32_t min_rechain_len = 1000;
|
|
580
|
+
const double min_rechain_ratio = 0.1;
|
|
581
|
+
uint32_t hash;
|
|
582
|
+
int32_t i, n_hit, hi_cov, is_sr;
|
|
583
|
+
int32_t sub_diff = opt->a + opt->b > opt->q + opt->e? opt->a + opt->b : opt->q + opt->e;
|
|
584
|
+
uint64_t *w;
|
|
585
|
+
double chn_pen_gap, seed_ratio;
|
|
586
|
+
uint8_t *seq;
|
|
587
|
+
mb_anchor_v v = {0,0,0};
|
|
588
|
+
mb_anchor_t *a;
|
|
589
|
+
mb_hit_t *hit;
|
|
590
|
+
|
|
591
|
+
if (kom_dbg_flag & MB_DBG_QNAME) fprintf(stderr, "QN\t%s\n", qname);
|
|
592
|
+
|
|
593
|
+
*n_hit_ = 0;
|
|
594
|
+
if (u->n == 0) {
|
|
595
|
+
kfree(b->km, u->a);
|
|
596
|
+
return 0;
|
|
597
|
+
}
|
|
598
|
+
hash = qname? mb_hash_str(qname) : 0;
|
|
599
|
+
hash ^= mb_hash64(qlen) + mb_hash64(opt->seed);
|
|
600
|
+
hash = mb_hash64(hash);
|
|
601
|
+
seq = kmalloc(b->km, qlen);
|
|
602
|
+
for (i = 0; i < qlen; ++i) seq[i] = kom_nt4_table[(uint8_t)seq0[i]];
|
|
603
|
+
hi_cov = mb_cal_high_cov(b->km, u->n, u->a, opt->max_occ);
|
|
604
|
+
is_sr = mb_is_sr_mode(opt, qlen);
|
|
605
|
+
|
|
606
|
+
// collect anchors
|
|
607
|
+
chn_pen_gap = opt->chain_gap_scale * .01 * opt->min_len;
|
|
608
|
+
if (kom_dbg_flag & MB_DBG_SEED) mb_dbg_seed(u->n, u->a, qname);
|
|
609
|
+
seed_ratio = mb_anchor(b->km, idx, u, opt->min_len, qlen, seq, mt, opt->max_occ, &v);
|
|
610
|
+
kfree(b->km, u->a); // no longer needed
|
|
611
|
+
u->n = 0, u->a = 0;
|
|
612
|
+
|
|
613
|
+
// initial chaining
|
|
614
|
+
if (kom_dbg_flag & MB_DBG_ANCHOR) mb_dbg_anchor(idx, qlen, v.n, v.a, qname);
|
|
615
|
+
a = mb_lchain_dp(b->km, idx->l2b, opt->max_gap, opt->max_gap, opt->bw, opt->max_chain_skip, opt->max_chain_iter,
|
|
616
|
+
opt->min_chain_score, chn_pen_gap, v.n, v.a, &n_hit, &w);
|
|
617
|
+
v.a = 0; v.n = v.m = 0; // ownership transferred to a
|
|
618
|
+
|
|
619
|
+
// re-chaining
|
|
620
|
+
if (opt->bw_long > opt->bw * 2 && !is_sr && n_hit > 0) {
|
|
621
|
+
int64_t n_a, as, st, en;
|
|
622
|
+
int32_t best;
|
|
623
|
+
// chains in w[] are sorted by tpos of first anchor, not by score; find the best
|
|
624
|
+
for (i = 1, best = 0; i < n_hit; ++i)
|
|
625
|
+
if ((w[i] >> 32) > (w[best] >> 32)) best = i;
|
|
626
|
+
for (i = 0, as = 0; i < best; ++i) as += (int32_t)w[i];
|
|
627
|
+
st = a[as].qpos + 1 - a[as].len;
|
|
628
|
+
en = a[as + (int32_t)w[best] - 1].qpos + 1;
|
|
629
|
+
if (qlen - (en - st) > min_rechain_len && en - st > qlen * min_rechain_ratio) {
|
|
630
|
+
for (i = 0, n_a = 0; i < n_hit; ++i) n_a += (int32_t)w[i];
|
|
631
|
+
kfree(b->km, w);
|
|
632
|
+
mb_anchor_sort(idx->l2b, n_a, a);
|
|
633
|
+
a = mb_lchain_dp(b->km, idx->l2b, opt->max_gap, opt->max_gap, opt->bw_long, opt->max_chain_skip, opt->max_chain_iter,
|
|
634
|
+
opt->min_chain_score, chn_pen_gap, n_a, a, &n_hit, &w);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// chain ordering
|
|
639
|
+
hit = mb_gen_hit(b->km, hash, qlen, idx->l2b, n_hit, w, a);
|
|
640
|
+
kfree(b->km, w);
|
|
641
|
+
mb_set_parent(b->km, opt->mask_level, opt->mask_len, n_hit, hit, sub_diff, 0);
|
|
642
|
+
mb_select_sub(b->km, opt->pri_ratio, opt->min_len * 2, opt->best_n, &n_hit, hit);
|
|
643
|
+
|
|
644
|
+
// base alignment
|
|
645
|
+
if (!(opt->flag & MB_F_NO_ALN)) {
|
|
646
|
+
hit = mb_align_skeleton(b->km, opt, idx, qlen, seq, mt, &n_hit, hit, a);
|
|
647
|
+
mb_set_parent(b->km, opt->mask_level, opt->mask_len, n_hit, hit, sub_diff, 0);
|
|
648
|
+
mb_select_sub(b->km, opt->pri_ratio, opt->min_len * 2, opt->best_n, &n_hit, hit);
|
|
649
|
+
mb_set_sam_pri(n_hit, hit, !!(opt->flag & MB_F_PRIMARY5));
|
|
650
|
+
}
|
|
651
|
+
for (i = 0; i < n_hit; ++i) {
|
|
652
|
+
hit[i].frac_high = (int32_t)(255. * hi_cov / qlen);
|
|
653
|
+
hit[i].seed_ratio = (int32_t)(255. * seed_ratio + .499);
|
|
654
|
+
if (hit[i].seed_ratio == 0) hit[i].seed_ratio = 1;
|
|
655
|
+
}
|
|
656
|
+
mb_set_mapq(b->km, qlen, n_hit, hit, opt->min_chain_score, opt->a, is_sr, opt->max_sr_len);
|
|
657
|
+
|
|
658
|
+
// clean up
|
|
659
|
+
kfree(b->km, a);
|
|
660
|
+
kfree(b->km, seq);
|
|
661
|
+
*n_hit_ = n_hit;
|
|
662
|
+
return hit;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/*************************
|
|
666
|
+
* Public alignment APIs *
|
|
667
|
+
*************************/
|
|
668
|
+
|
|
669
|
+
mb_hit_t *mb_map(const mb_opt_t *opt, const mb_idx_t *idx, int32_t qlen, const char *seq0, int32_t mt0, int32_t *n_hit_, mb_tbuf_t *b0, const char *qname)
|
|
670
|
+
{
|
|
671
|
+
mb_opt_t opt_adap;
|
|
672
|
+
mb_hit_t *ret;
|
|
673
|
+
mb_sai_v u = {0,0,0};
|
|
674
|
+
mb_tbuf_t *b;
|
|
675
|
+
uint8_t *seq;
|
|
676
|
+
int32_t i;
|
|
677
|
+
l2b_meth_t mt = mt0 == 0? L2B_METH_NONE : mt0 == 1? L2B_METH_C2T : L2B_METH_G2A;
|
|
678
|
+
if (mt != L2B_METH_NONE && !idx->is_meth) { *n_hit_ = 0; return 0; }
|
|
679
|
+
b = b0? b0 : mb_tbuf_init(1);
|
|
680
|
+
mb_opt_adap(opt, qlen, &opt_adap);
|
|
681
|
+
if (mt != L2B_METH_NONE) opt_adap.flag |= MB_F_METH; // needed in mb_map_sai()
|
|
682
|
+
seq = Kmalloc(b->km, uint8_t, qlen);
|
|
683
|
+
for (i = 0; i < qlen; ++i)
|
|
684
|
+
seq[i] = kom_nt4_table[(uint8_t)seq0[i]];
|
|
685
|
+
if (mt != L2B_METH_NONE)
|
|
686
|
+
l2b_meth_convert(mt, qlen, seq);
|
|
687
|
+
mb_seed_intv(b->km, idx->bwt, qlen, seq, opt->min_len, opt->max_sub_occ, &u);
|
|
688
|
+
kfree(b->km, seq);
|
|
689
|
+
ret = mb_map_sai(&opt_adap, idx, qlen, seq0, mt, &u, n_hit_, b, qname);
|
|
690
|
+
if (b0 == 0) mb_tbuf_destroy(b);
|
|
691
|
+
return ret;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
mb_hit_t **mb_map_batch(const mb_opt_t *opt, const mb_idx_t *idx, int32_t n_seq, const int32_t *qlen, const char **seq, int32_t *n_hit, mb_tbuf_t *b0, const char **qname)
|
|
695
|
+
{
|
|
696
|
+
mb_tbuf_t *b;
|
|
697
|
+
mb_hit_t **hit;
|
|
698
|
+
mb_sai_v *sai;
|
|
699
|
+
uint8_t **seq4;
|
|
700
|
+
void *km;
|
|
701
|
+
int32_t i, j, k, sb_st, sb_len, sb_max, is_pe = !!(opt->flag & MB_F_PE), is_meth = !!(opt->flag & MB_F_METH);
|
|
702
|
+
|
|
703
|
+
if (n_seq <= 0) return 0;
|
|
704
|
+
if (is_meth && !idx->is_meth) return 0;
|
|
705
|
+
b = b0? b0 : mb_tbuf_init(0);
|
|
706
|
+
km = mb_tbuf_km(b);
|
|
707
|
+
hit = (mb_hit_t**)calloc(n_seq, sizeof(mb_hit_t*));
|
|
708
|
+
|
|
709
|
+
// pre-allocate for sub-batch processing
|
|
710
|
+
sb_max = opt->sb_seq < n_seq? opt->sb_seq : n_seq;
|
|
711
|
+
seq4 = Kmalloc(km, uint8_t*, sb_max);
|
|
712
|
+
sai = Kmalloc(km, mb_sai_v, sb_max);
|
|
713
|
+
|
|
714
|
+
// process in sub-batches
|
|
715
|
+
for (i = 0, sb_st = 0, sb_len = 0; i <= n_seq; ++i) {
|
|
716
|
+
if (i == n_seq || sb_len >= opt->sb_len || i - sb_st >= opt->sb_seq) {
|
|
717
|
+
int32_t sb_n = i - sb_st;
|
|
718
|
+
if (sb_n == 0) { sb_st = i; sb_len = 0; continue; }
|
|
719
|
+
|
|
720
|
+
// convert sub-batch to 4-bit encoding
|
|
721
|
+
for (k = 0; k < sb_n; ++k) {
|
|
722
|
+
int32_t idx_k = sb_st + k;
|
|
723
|
+
l2b_meth_t mt = !is_meth? L2B_METH_NONE : !is_pe || (idx_k&1) == 0? L2B_METH_C2T : L2B_METH_G2A;
|
|
724
|
+
seq4[k] = Kmalloc(km, uint8_t, qlen[idx_k]);
|
|
725
|
+
for (j = 0; j < qlen[idx_k]; ++j)
|
|
726
|
+
seq4[k][j] = kom_nt4_table[(uint8_t)seq[idx_k][j]];
|
|
727
|
+
if (mt != L2B_METH_NONE) l2b_meth_convert(mt, qlen[idx_k], seq4[k]);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
// batch SMEM for sub-batch
|
|
731
|
+
memset(sai, 0, sb_n * sizeof(mb_sai_v));
|
|
732
|
+
mb_seed_intv_batch(km, idx->bwt, sb_n, &qlen[sb_st], seq4, opt->min_len, opt->max_sub_occ, sai);
|
|
733
|
+
for (k = 0; k < sb_n; ++k) kfree(km, seq4[k]);
|
|
734
|
+
|
|
735
|
+
// map each sequence in sub-batch
|
|
736
|
+
for (k = 0; k < sb_n; ++k) {
|
|
737
|
+
int32_t idx_k = sb_st + k;
|
|
738
|
+
mb_opt_t opt_adap;
|
|
739
|
+
l2b_meth_t mt = !is_meth? L2B_METH_NONE : !is_pe || (idx_k&1) == 0? L2B_METH_C2T : L2B_METH_G2A;
|
|
740
|
+
mb_opt_adap(opt, qlen[idx_k], &opt_adap);
|
|
741
|
+
hit[idx_k] = mb_map_sai(&opt_adap, idx, qlen[idx_k], seq[idx_k], mt, &sai[k], &n_hit[idx_k], b, qname? qname[idx_k] : 0);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
sb_st = i;
|
|
745
|
+
sb_len = 0;
|
|
746
|
+
}
|
|
747
|
+
if (i < n_seq) sb_len += qlen[i];
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
kfree(km, sai);
|
|
751
|
+
kfree(km, seq4);
|
|
752
|
+
|
|
753
|
+
// paired-end processing
|
|
754
|
+
if (is_pe && n_seq >= 2) {
|
|
755
|
+
mb_pestat_t pes[4];
|
|
756
|
+
for (i = 0; i < 4; ++i) pes[i].failed = 1;
|
|
757
|
+
pes[1].failed = 0;
|
|
758
|
+
pes[1].avg = opt->pe_avg, pes[1].std = opt->pe_std;
|
|
759
|
+
pes[1].lo = opt->pe_lo, pes[1].hi = opt->pe_hi;
|
|
760
|
+
for (i = 0; i + 1 < n_seq; i += 2) {
|
|
761
|
+
int32_t len2[2] = { qlen[i], qlen[i+1] };
|
|
762
|
+
char *seq2[2] = { (char*)seq[i], (char*)seq[i+1] };
|
|
763
|
+
mb_pair(km, opt, idx->l2b, &n_hit[i], &hit[i], pes, len2, seq2);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
if (b0 == 0) mb_tbuf_destroy(b);
|
|
768
|
+
return hit;
|
|
769
|
+
}
|