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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +119 -0
  4. data/ext/minibwa/extconf.rb +105 -0
  5. data/ext/minibwa/mb_buffer.c +113 -0
  6. data/ext/minibwa/mb_hit.c +192 -0
  7. data/ext/minibwa/mb_index.c +462 -0
  8. data/ext/minibwa/mb_index_build.c +174 -0
  9. data/ext/minibwa/mb_options.c +301 -0
  10. data/ext/minibwa/minibwa/LICENSE.txt +37 -0
  11. data/ext/minibwa/minibwa/align.c +930 -0
  12. data/ext/minibwa/minibwa/bseq.h +45 -0
  13. data/ext/minibwa/minibwa/bwt.c +715 -0
  14. data/ext/minibwa/minibwa/bwt.h +86 -0
  15. data/ext/minibwa/minibwa/cs.c +161 -0
  16. data/ext/minibwa/minibwa/format.c +356 -0
  17. data/ext/minibwa/minibwa/index.c +342 -0
  18. data/ext/minibwa/minibwa/kalloc.c +224 -0
  19. data/ext/minibwa/minibwa/kalloc.h +54 -0
  20. data/ext/minibwa/minibwa/ketopt.h +123 -0
  21. data/ext/minibwa/minibwa/kommon.c +374 -0
  22. data/ext/minibwa/minibwa/kommon.h +85 -0
  23. data/ext/minibwa/minibwa/kseq.h +256 -0
  24. data/ext/minibwa/minibwa/ksort.h +163 -0
  25. data/ext/minibwa/minibwa/ksw2.h +220 -0
  26. data/ext/minibwa/minibwa/ksw2_extd2_sse.c +403 -0
  27. data/ext/minibwa/minibwa/ksw2_extz2_sse.c +296 -0
  28. data/ext/minibwa/minibwa/ksw2_ll_sse.c +341 -0
  29. data/ext/minibwa/minibwa/kthread.h +15 -0
  30. data/ext/minibwa/minibwa/l2bit.c +479 -0
  31. data/ext/minibwa/minibwa/l2bit.h +72 -0
  32. data/ext/minibwa/minibwa/lchain.c +231 -0
  33. data/ext/minibwa/minibwa/libsais.c +6985 -0
  34. data/ext/minibwa/minibwa/libsais.h +106 -0
  35. data/ext/minibwa/minibwa/libsais64.c +7064 -0
  36. data/ext/minibwa/minibwa/libsais64.h +81 -0
  37. data/ext/minibwa/minibwa/map-algo.c +769 -0
  38. data/ext/minibwa/minibwa/mbpriv.h +148 -0
  39. data/ext/minibwa/minibwa/minibwa.h +176 -0
  40. data/ext/minibwa/minibwa/options.c +116 -0
  41. data/ext/minibwa/minibwa/pe.c +559 -0
  42. data/ext/minibwa/minibwa/s2n-lite.h +59 -0
  43. data/ext/minibwa/minibwa/seed.c +354 -0
  44. data/ext/minibwa/minibwa.c +67 -0
  45. data/ext/minibwa/minibwa.h +51 -0
  46. data/lib/minibwa/hit.rb +110 -0
  47. data/lib/minibwa/index.rb +77 -0
  48. data/lib/minibwa/options.rb +235 -0
  49. data/lib/minibwa/sam.rb +85 -0
  50. data/lib/minibwa/version.rb +6 -0
  51. data/lib/minibwa.rb +11 -0
  52. 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 = &regs[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 = &regs[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 = &regs[(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 = &regs[aux[i].y];
494
+ if (inv->inv) {
495
+ mb_hit_t *l = &regs[aux[i-1].y];
496
+ mb_hit_t *r = &regs[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 = &regs[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
+ }