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,930 @@
1
+ #include <assert.h>
2
+ #include <string.h>
3
+ #include <stdlib.h>
4
+ #include <stdio.h>
5
+ #include <math.h>
6
+ #include "mbpriv.h"
7
+ #include "kommon.h"
8
+ #include "kalloc.h"
9
+ #include "ksw2.h"
10
+
11
+ static inline void update_max_zdrop(int32_t score, int i, int j, int32_t *max, int *max_i, int *max_j, int e, int *max_zdrop, int pos[2][2])
12
+ {
13
+ if (score < *max) {
14
+ int li = i - *max_i;
15
+ int lj = j - *max_j;
16
+ int diff = li > lj? li - lj : lj - li;
17
+ int z = *max - score - diff * e;
18
+ if (z > *max_zdrop) {
19
+ *max_zdrop = z;
20
+ pos[0][0] = *max_i, pos[0][1] = i;
21
+ pos[1][0] = *max_j, pos[1][1] = j;
22
+ }
23
+ } else *max = score, *max_i = i, *max_j = j;
24
+ }
25
+
26
+ static int mm_test_zdrop(void *km, const mb_opt_t *opt, const uint8_t *qseq, const uint8_t *tseq, uint32_t n_cigar, uint32_t *cigar, const int8_t *mat, int32_t is_sr)
27
+ {
28
+ uint32_t k;
29
+ int32_t score = 0, max = INT32_MIN, max_i = -1, max_j = -1, i = 0, j = 0, max_zdrop = 0;
30
+ int pos[2][2] = {{-1, -1}, {-1, -1}}, q_len, t_len;
31
+
32
+ // find the score and the region where score drops most along diagonal
33
+ for (k = 0, score = 0; k < n_cigar; ++k) {
34
+ uint32_t l, op = cigar[k]&0xf, len = cigar[k]>>4;
35
+ if (op == MB_CIGAR_MATCH) {
36
+ for (l = 0; l < len; ++l) {
37
+ score += mat[tseq[i + l] * 5 + qseq[j + l]];
38
+ update_max_zdrop(score, i+l, j+l, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
39
+ }
40
+ i += len, j += len;
41
+ } else if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL || op == MB_CIGAR_N_SKIP) {
42
+ score -= opt->q + opt->e * len;
43
+ if (op == MB_CIGAR_INS) j += len;
44
+ else i += len;
45
+ update_max_zdrop(score, i, j, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
46
+ }
47
+ }
48
+
49
+ // test if there is an inversion in the most dropped region
50
+ q_len = pos[1][1] - pos[1][0], t_len = pos[0][1] - pos[0][0];
51
+ if (!is_sr && max_zdrop > opt->zdrop_inv && q_len < opt->max_gap && t_len < opt->max_gap) {
52
+ uint8_t *qseq2;
53
+ void *qp;
54
+ int q_off, t_off;
55
+ qseq2 = Kmalloc(km, uint8_t, q_len);
56
+ for (i = 0; i < q_len; ++i) {
57
+ int c = qseq[pos[1][1] - i - 1];
58
+ qseq2[i] = c >= 4? 4 : 3 - c;
59
+ }
60
+ qp = ksw_ll_qinit(km, 2, q_len, qseq2, 5, mat);
61
+ score = ksw_ll_i16(qp, t_len, tseq + pos[0][0], opt->q, opt->e, &q_off, &t_off);
62
+ kfree(km, qseq2);
63
+ kfree(km, qp);
64
+ if (score >= opt->min_chain_score * opt->a && score >= opt->min_dp_max * opt->a)
65
+ return 2; // there is a potential inversion
66
+ }
67
+ return max_zdrop > opt->zdrop? 1 : 0;
68
+ }
69
+
70
+ static void mb_fix_cigar(mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq, int *qshift, int *tshift)
71
+ {
72
+ mb_extra_t *p = r->p;
73
+ int32_t toff = 0, qoff = 0, to_shrink = 0;
74
+ uint32_t k;
75
+ *qshift = *tshift = 0;
76
+ if (p->n_cigar <= 1) return;
77
+ for (k = 0; k < p->n_cigar; ++k) { // indel left alignment
78
+ uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
79
+ if (len == 0) to_shrink = 1;
80
+ if (op == MB_CIGAR_MATCH) {
81
+ toff += len, qoff += len;
82
+ } else if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL) {
83
+ if (k > 0 && k < p->n_cigar - 1 && (p->cigar[k-1]&0xf) == 0 && (p->cigar[k+1]&0xf) == 0) {
84
+ int l, prev_len = p->cigar[k-1] >> 4;
85
+ if (op == MB_CIGAR_INS) {
86
+ for (l = 0; l < prev_len; ++l)
87
+ if (qseq[qoff - 1 - l] != qseq[qoff + len - 1 - l])
88
+ break;
89
+ } else {
90
+ for (l = 0; l < prev_len; ++l)
91
+ if (tseq[toff - 1 - l] != tseq[toff + len - 1 - l])
92
+ break;
93
+ }
94
+ if (l > 0)
95
+ p->cigar[k-1] -= l<<4, p->cigar[k+1] += l<<4, qoff -= l, toff -= l;
96
+ if (l == prev_len) to_shrink = 1;
97
+ }
98
+ if (op == MB_CIGAR_INS) qoff += len;
99
+ else toff += len;
100
+ } else if (op == MB_CIGAR_N_SKIP) {
101
+ toff += len;
102
+ }
103
+ }
104
+ assert(qoff == r->qe - r->qs && toff == r->te - r->ts);
105
+ for (k = 0; k < p->n_cigar - 2; ++k) { // fix CIGAR like 5I6D7I
106
+ if ((p->cigar[k]&0xf) > 0 && (p->cigar[k]&0xf) + (p->cigar[k+1]&0xf) == 3) {
107
+ uint32_t l, s[3] = {0,0,0};
108
+ for (l = k; l < p->n_cigar; ++l) { // count number of adjacent I and D
109
+ uint32_t op = p->cigar[l]&0xf;
110
+ if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL || p->cigar[l]>>4 == 0)
111
+ s[op] += p->cigar[l] >> 4;
112
+ else break;
113
+ }
114
+ if (s[1] > 0 && s[2] > 0 && l - k > 2) { // turn to a single I and a single D
115
+ p->cigar[k] = s[1]<<4|MB_CIGAR_INS;
116
+ p->cigar[k+1] = s[2]<<4|MB_CIGAR_DEL;
117
+ for (k += 2; k < l; ++k)
118
+ p->cigar[k] &= 0xf;
119
+ to_shrink = 1;
120
+ }
121
+ k = l;
122
+ }
123
+ }
124
+ if (to_shrink) { // squeeze out zero-length operations
125
+ int32_t l = 0;
126
+ for (k = 0; k < p->n_cigar; ++k) // squeeze out zero-length operations
127
+ if (p->cigar[k]>>4 != 0)
128
+ p->cigar[l++] = p->cigar[k];
129
+ p->n_cigar = l;
130
+ for (k = l = 0; k < p->n_cigar; ++k) // merge two adjacent operations if they are the same
131
+ if (k == p->n_cigar - 1 || (p->cigar[k]&0xf) != (p->cigar[k+1]&0xf))
132
+ p->cigar[l++] = p->cigar[k];
133
+ else p->cigar[k+1] += p->cigar[k]>>4<<4; // add length to the next CIGAR operator
134
+ p->n_cigar = l;
135
+ }
136
+ if ((p->cigar[0]&0xf) == MB_CIGAR_INS || (p->cigar[0]&0xf) == MB_CIGAR_DEL) { // get rid of leading I or D
137
+ int32_t l = p->cigar[0] >> 4;
138
+ if ((p->cigar[0]&0xf) == MB_CIGAR_INS) {
139
+ if (r->rev) r->qe -= l;
140
+ else r->qs += l;
141
+ *qshift = l;
142
+ } else r->ts += l, *tshift = l;
143
+ --p->n_cigar;
144
+ memmove(p->cigar, p->cigar + 1, p->n_cigar * 4);
145
+ }
146
+ }
147
+
148
+ static void mm_update_cigar_eqx(mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq) // written by @armintoepfer
149
+ {
150
+ uint32_t n_EQX = 0, n_X = 0;
151
+ uint32_t k, l, m, cap, toff = 0, qoff = 0, n_M = 0;
152
+ mb_extra_t *p;
153
+ if (r->p == 0) return;
154
+ for (k = 0; k < r->p->n_cigar; ++k) {
155
+ uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
156
+ if (op == MB_CIGAR_MATCH) {
157
+ while (len > 0) {
158
+ for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4; ++l) {} // run of "="; N is a mismatch (cf. e41830b for NM)
159
+ if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
160
+ for (l = 0; l < len && !(qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4); ++l) {} // run of "X" (includes N<=>N)
161
+ if (l > 0) { ++n_EQX; ++n_X; len -= l; toff += l; qoff += l; }
162
+ }
163
+ ++n_M;
164
+ } else if (op == MB_CIGAR_INS) {
165
+ qoff += len;
166
+ } else if (op == MB_CIGAR_DEL) {
167
+ toff += len;
168
+ } else if (op == MB_CIGAR_N_SKIP) {
169
+ toff += len;
170
+ }
171
+ }
172
+ // update in-place only if every M op is a single pure "=" run (no "X",
173
+ // hence no mismatch or N); otherwise the emission pass below is needed
174
+ if (n_X == 0) {
175
+ for (k = 0; k < r->p->n_cigar; ++k) {
176
+ uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
177
+ if (op == MB_CIGAR_MATCH) r->p->cigar[k] = len << 4 | MB_CIGAR_EQ_MATCH;
178
+ }
179
+ return;
180
+ }
181
+ // allocate new storage
182
+ cap = r->p->n_cigar + (n_EQX - n_M) + sizeof(mb_extra_t);
183
+ kom_roundup32(cap);
184
+ p = (mb_extra_t*)calloc(cap, 4);
185
+ memcpy(p, r->p, sizeof(mb_extra_t));
186
+ p->cap = cap;
187
+ // update cigar while copying
188
+ toff = qoff = m = 0;
189
+ for (k = 0; k < r->p->n_cigar; ++k) {
190
+ uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
191
+ if (op == MB_CIGAR_MATCH) {
192
+ while (len > 0) {
193
+ // match ("="); N is a mismatch, so require both bases < 4
194
+ for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4; ++l) {}
195
+ if (l > 0) p->cigar[m++] = l << 4 | MB_CIGAR_EQ_MATCH;
196
+ len -= l;
197
+ toff += l, qoff += l;
198
+ // mismatch ("X"); includes N<=>N
199
+ for (l = 0; l < len && !(qseq[qoff + l] == tseq[toff + l] && qseq[qoff + l] < 4); ++l) {}
200
+ if (l > 0) p->cigar[m++] = l << 4 | MB_CIGAR_X_MISMATCH;
201
+ len -= l;
202
+ toff += l, qoff += l;
203
+ }
204
+ continue;
205
+ } else if (op == MB_CIGAR_INS) {
206
+ qoff += len;
207
+ } else if (op == MB_CIGAR_DEL) {
208
+ toff += len;
209
+ } else if (op == MB_CIGAR_N_SKIP) {
210
+ toff += len;
211
+ }
212
+ p->cigar[m++] = r->p->cigar[k];
213
+ }
214
+ p->n_cigar = m;
215
+ free(r->p);
216
+ r->p = p;
217
+ }
218
+
219
+ void mb_update_extra(void *km, mb_hit_t *r, const uint8_t *qseq, const uint8_t *tseq, const int8_t *mat, int8_t q, int8_t e, uint64_t opt_flag, int log_gap)
220
+ {
221
+ uint32_t k, l;
222
+ int32_t qshift, tshift, toff = 0, qoff = 0, len4;
223
+ double s = 0.0, max = 0.0;
224
+ mb_extra_t *p = r->p;
225
+ if (p == 0) return;
226
+ mb_fix_cigar(r, qseq, tseq, &qshift, &tshift);
227
+ qseq += qshift, tseq += tshift; // qseq and tseq may be shifted due to the removal of leading I/D
228
+ r->blen = r->mlen = 0;
229
+ for (k = 0; k < p->n_cigar; ++k) {
230
+ uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
231
+ if (op == MB_CIGAR_MATCH) {
232
+ int n_ambi = 0, n_diff = 0;
233
+ for (l = 0; l < len; ++l) {
234
+ int cq = qseq[qoff + l], ct = tseq[toff + l];
235
+ if (ct > 3 || cq > 3) ++n_ambi;
236
+ else if (ct != cq) n_diff += (mat[ct * 5 + cq] < 0);
237
+ s += mat[ct * 5 + cq];
238
+ if (s < 0) s = 0;
239
+ else max = max > s? max : s;
240
+ }
241
+ r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
242
+ toff += len, qoff += len;
243
+ } else if (op == MB_CIGAR_INS) {
244
+ int n_ambi = 0;
245
+ for (l = 0; l < len; ++l)
246
+ if (qseq[qoff + l] > 3) ++n_ambi;
247
+ r->blen += len - n_ambi, p->n_ambi += n_ambi;
248
+ if (log_gap) s -= q + (double)e * mb_log2(1.0 + len);
249
+ else s -= q + e;
250
+ if (s < 0) s = 0;
251
+ qoff += len;
252
+ } else if (op == MB_CIGAR_DEL) {
253
+ int n_ambi = 0;
254
+ for (l = 0; l < len; ++l)
255
+ if (tseq[toff + l] > 3) ++n_ambi;
256
+ r->blen += len - n_ambi, p->n_ambi += n_ambi;
257
+ if (log_gap) s -= q + (double)e * mb_log2(1.0 + len);
258
+ else s -= q + e;
259
+ if (s < 0) s = 0;
260
+ toff += len;
261
+ }
262
+ }
263
+ p->dp_max0 = p->dp_max = (int32_t)(max + .499);
264
+ assert(qoff == r->qe - r->qs && toff == r->te - r->ts);
265
+ if (opt_flag & MB_F_EQX) mm_update_cigar_eqx(r, qseq, tseq); // NB: it has to be called here as changes to qseq and tseq are not returned
266
+ if (opt_flag & (MB_F_WRITE_DS|MB_F_WRITE_CS|MB_F_WRITE_MD)) {
267
+ kstring_t str = {0,0,0};
268
+ str.m = 256;
269
+ str.s = kmalloc(km, str.m);
270
+ if (opt_flag & (MB_F_WRITE_DS|MB_F_WRITE_CS))
271
+ mb_write_cs_ds(km, &str, tseq, qseq, r, !!(opt_flag & MB_F_WRITE_DS));
272
+ else
273
+ mb_write_MD(km, &str, tseq, qseq, r);
274
+ r->p->cs = 1;
275
+ len4 = r->p->n_cigar + sizeof(mb_extra_t)/4 + (str.l + 1 + 3) / 4;
276
+ if (len4 > r->p->cap) {
277
+ r->p->cap = len4;
278
+ r->p = (mb_extra_t*)realloc(r->p, r->p->cap * 4);
279
+ }
280
+ memcpy(&r->p->cigar[r->p->n_cigar], str.s, str.l + 1);
281
+ kfree(km, str.s);
282
+ }
283
+ }
284
+
285
+ static void mb_enlarge_cigar(mb_hit_t *r, uint32_t n_cigar) // TODO: this calls the libc realloc()
286
+ {
287
+ if (n_cigar == 0) return;
288
+ if (r->p == 0) {
289
+ uint32_t cap = n_cigar + sizeof(mb_extra_t)/4;
290
+ kom_roundup32(cap);
291
+ r->p = (mb_extra_t*)calloc(cap, 4);
292
+ r->p->cap = cap;
293
+ } else if (r->p->n_cigar + n_cigar + sizeof(mb_extra_t)/4 > r->p->cap) {
294
+ r->p->cap = r->p->n_cigar + n_cigar + sizeof(mb_extra_t)/4;
295
+ kom_roundup32(r->p->cap);
296
+ r->p = (mb_extra_t*)realloc(r->p, r->p->cap * 4);
297
+ }
298
+ }
299
+
300
+ void mb_append_cigar(mb_hit_t *r, uint32_t n_cigar, const uint32_t *cigar)
301
+ {
302
+ mb_extra_t *p;
303
+ if (n_cigar == 0) return;
304
+ mb_enlarge_cigar(r, n_cigar);
305
+ p = r->p;
306
+ if (p->n_cigar > 0 && (p->cigar[p->n_cigar-1]&0xf) == (cigar[0]&0xf)) { // same CIGAR op at the boundary
307
+ p->cigar[p->n_cigar-1] += cigar[0]>>4<<4;
308
+ if (n_cigar > 1) memcpy(p->cigar + p->n_cigar, cigar + 1, (n_cigar - 1) * 4);
309
+ p->n_cigar += n_cigar - 1;
310
+ } else {
311
+ memcpy(p->cigar + p->n_cigar, cigar, n_cigar * 4);
312
+ p->n_cigar += n_cigar;
313
+ }
314
+ }
315
+
316
+ static inline int32_t mb_min_int32(int32_t a, int32_t b)
317
+ {
318
+ return a < b? a : b;
319
+ }
320
+
321
+ static inline int32_t max_bw_from_mm(const mb_opt_t *opt, int32_t mm)
322
+ {
323
+ int32_t x = mm * (opt->a + opt->b), max2 = 0, max1 = 0;
324
+ if (x >= opt->q + opt->e) max1 = (x - opt->q + opt->e - 1) / opt->e;
325
+ if (x >= opt->q2 + opt->e2) max2 = (x - opt->q2 + opt->e2 - 1) / opt->e2;
326
+ return max1 > max2? max1 : max2;
327
+ }
328
+
329
+ static void mb_align_pair(void *km, const mb_opt_t *opt, int qlen, const uint8_t *qseq, int tlen, const uint8_t *tseq,
330
+ const int8_t *mat, int w, int end_bonus, int zdrop, int ksw_flag, ksw_extz_t *ez)
331
+ {
332
+ const int max_bw_adj_len = 100; // don't adjust bandwidth if sequences are too long
333
+ int32_t j, n_mm = -1;
334
+ if ((opt->b_ts != 0 && opt->b != opt->b_ts) || (opt->flag&MB_F_METH))
335
+ ksw_flag |= KSW_EZ_GENERIC_SC;
336
+ if ((ksw_flag & KSW_EZ_EXTZ_ONLY) && tlen >= qlen) { // ungapped extension
337
+ ksw_reset_extz(ez);
338
+ for (j = 0, ez->score = ez->max = 0; j < qlen; ++j) {
339
+ ez->score += mat[tseq[j] * 5 + qseq[j]];
340
+ n_mm += (tseq[j] > 3 || qseq[j] > 3 || mat[tseq[j] * 5 + qseq[j]] < 0);
341
+ if (ez->max < ez->score) ez->max = ez->score, ez->max_q = ez->max_t = j;
342
+ }
343
+ if (n_mm <= 2) {
344
+ ez->mqe = ez->score, ez->mqe_t = qlen - 1;
345
+ if (ez->mqe + end_bonus >= ez->max) {
346
+ ez->reach_end = 1;
347
+ ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, MB_CIGAR_MATCH, qlen);
348
+ return;
349
+ }
350
+ }
351
+ } else if (qlen == tlen && !(ksw_flag & KSW_EZ_EXTZ_ONLY)) { // ungapped alignment
352
+ int32_t max_gapped_score = (qlen - 2) * opt->a - 2 * (opt->q + opt->e);
353
+ ksw_reset_extz(ez);
354
+ for (j = 0, ez->score = 0; j < qlen; ++j) {
355
+ ez->score += mat[tseq[j] * 5 + qseq[j]];
356
+ n_mm += (tseq[j] > 3 || qseq[j] > 3 || mat[tseq[j] * 5 + qseq[j]] < 0);
357
+ }
358
+ if (n_mm <= 3 || ez->score > max_gapped_score) {
359
+ ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, MB_CIGAR_MATCH, qlen);
360
+ return;
361
+ }
362
+ }
363
+
364
+ if (n_mm >= 0 && mb_min_int32(qlen, tlen) < max_bw_adj_len) { // n_mm >= 0 => ungapped alignment attempted
365
+ int32_t max_bw;
366
+ max_bw = max_bw_from_mm(opt, n_mm);
367
+ if (w > max_bw + 4) w = max_bw + 4;
368
+ }
369
+
370
+ if (opt->max_sw_mat > 0 && (int64_t)tlen * qlen > opt->max_sw_mat) { // too much memory; skip alignment
371
+ ksw_reset_extz(ez);
372
+ ez->zdropped = 1;
373
+ } else if (opt->q == opt->q2 && opt->e == opt->e2) { // affine gap
374
+ ksw_extz2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, w, zdrop * opt->a, end_bonus, ksw_flag, ez);
375
+ } else { // dual affine gap
376
+ ksw_extd2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->e2, w, zdrop * opt->a, end_bonus, ksw_flag, ez);
377
+ //fprintf(stderr, "D2\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", tlen, qlen, !!(ksw_flag&KSW_EZ_EXTZ_ONLY), ez->max_t, ez->max_q, ez->max, ez->zdropped);
378
+ }
379
+ if (kom_dbg_flag & MB_DBG_ALN_SEQ) {
380
+ int i;
381
+ fprintf(stderr, "===> q=(%d,%d), e=(%d,%d), bw=%d, ksw_flag=0x%x, zdrop=%d, end_bonus=%d <===\n", opt->q, opt->q2, opt->e, opt->e2, w, ksw_flag, opt->zdrop, end_bonus);
382
+ for (i = 0; i < tlen; ++i) fputc("ACGTN"[tseq[i]], stderr);
383
+ fputc('\n', stderr);
384
+ for (i = 0; i < qlen; ++i) fputc("ACGTN"[qseq[i]], stderr);
385
+ fputc('\n', stderr);
386
+ fprintf(stderr, "score=%d, max=%d, cigar=", ez->score, ez->max);
387
+ for (i = 0; i < ez->n_cigar; ++i) fprintf(stderr, "%d%c", ez->cigar[i]>>4, MB_CIGAR_STR[ez->cigar[i]&0xf]);
388
+ fprintf(stderr, "\n");
389
+ }
390
+ }
391
+
392
+ static int *collect_long_gaps(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int *n_)
393
+ {
394
+ int i, n, *K;
395
+ *n_ = 0;
396
+ for (i = 1, n = 0; i < cnt1; ++i) { // count the number of gaps longer than min_gap
397
+ int64_t gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
398
+ if (gap < -min_gap || gap > min_gap) ++n;
399
+ }
400
+ if (n <= 1) return 0;
401
+ K = Kmalloc(km, int, n);
402
+ for (i = 1, n = 0; i < cnt1; ++i) { // store the positions of long gaps
403
+ int64_t gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
404
+ if (gap < -min_gap || gap > min_gap)
405
+ K[n++] = i;
406
+ }
407
+ *n_ = n;
408
+ return K;
409
+ }
410
+
411
+ static void mm_filter_bad_seeds(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int diff_thres, int max_ext_len, int max_ext_cnt)
412
+ { // this function deals with e.g. 1000I20M1000D
413
+ int max_st, max_en, n, i, k, max, *K;
414
+ K = collect_long_gaps(km, as1, cnt1, a, min_gap, &n);
415
+ if (K == 0) return;
416
+ max = 0, max_st = max_en = -1;
417
+ for (k = 0;; ++k) { // traverse long gaps
418
+ int gap, l, n_ins = 0, n_del = 0, qs, max_diff = 0, max_diff_l = -1;
419
+ int64_t ts;
420
+ if (k == n || k >= max_en) {
421
+ if (max_en > 0)
422
+ for (i = K[max_st]; i < K[max_en]; ++i)
423
+ a[as1 + i].flag |= MB_SEED_IGNORE;
424
+ max = 0, max_st = max_en = -1;
425
+ if (k == n) break;
426
+ }
427
+ i = K[k];
428
+ gap = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
429
+ if (gap > 0) n_ins += gap;
430
+ else n_del += -gap;
431
+ qs = a[as1 + i - 1].qpos;
432
+ ts = a[as1 + i - 1].tpos;
433
+ for (l = k + 1; l < n && l <= k + max_ext_cnt; ++l) {
434
+ int j = K[l], diff;
435
+ if (a[as1 + j].qpos - a[as1 + j].len - qs > max_ext_len || a[as1 + j].tpos - a[as1 + j].len - ts > max_ext_len) break;
436
+ gap = (a[as1 + j].qpos - a[as1 + j - 1].qpos) - (a[as1 + j].tpos - a[as1 + j - 1].tpos);
437
+ if (gap > 0) n_ins += gap;
438
+ else n_del += -gap;
439
+ diff = n_ins + n_del - abs(n_ins - n_del);
440
+ if (max_diff < diff)
441
+ max_diff = diff, max_diff_l = l;
442
+ }
443
+ if (max_diff > diff_thres && max_diff > max)
444
+ max = max_diff, max_st = k, max_en = max_diff_l;
445
+ }
446
+ kfree(km, K);
447
+ }
448
+
449
+ static void mm_filter_bad_seeds_alt(void *km, int as1, int cnt1, mb_anchor_t *a, int min_gap, int max_ext)
450
+ { // this function deals with e.g. 1000I20M2000I
451
+ int n, k, *K;
452
+ K = collect_long_gaps(km, as1, cnt1, a, min_gap, &n);
453
+ if (K == 0) return;
454
+ for (k = 0; k < n;) {
455
+ int i = K[k], l;
456
+ int gap1 = (a[as1 + i].qpos - a[as1 + i - 1].qpos) - (a[as1 + i].tpos - a[as1 + i - 1].tpos);
457
+ int64_t te1 = a[as1 + i].tpos;
458
+ int32_t qe1 = a[as1 + i].qpos;
459
+ int32_t left_len = a[as1 + i].len;
460
+ gap1 = gap1 > 0? gap1 : -gap1;
461
+ for (l = k + 1; l < n; ++l) {
462
+ int j = K[l], gap2, m;
463
+ if (a[as1 + j].qpos - qe1 > max_ext || a[as1 + j].tpos - te1 > max_ext) break;
464
+ gap2 = (a[as1 + j].qpos - a[as1 + j - 1].qpos) - (a[as1 + j].tpos - a[as1 + j - 1].tpos);
465
+ int64_t m_t = a[as1 + j - 1].tpos - te1 + left_len;
466
+ int32_t m_q = a[as1 + j - 1].qpos - qe1 + left_len;
467
+ m = m_t < m_q? m_t : m_q;
468
+ gap2 = gap2 > 0? gap2 : -gap2;
469
+ if (m > gap1 + gap2) break;
470
+ te1 = a[as1 + j].tpos;
471
+ qe1 = a[as1 + j].qpos;
472
+ left_len = a[as1 + j].len;
473
+ gap1 = gap2;
474
+ }
475
+ if (l > k + 1) {
476
+ int j, end = K[l - 1];
477
+ for (j = K[k]; j < end; ++j)
478
+ a[as1 + j].flag |= MB_SEED_IGNORE;
479
+ a[as1 + end].flag |= MB_SEED_LONG_JOIN;
480
+ }
481
+ k = l;
482
+ }
483
+ kfree(km, K);
484
+ }
485
+
486
+ static void mm_fix_bad_ends(const mb_hit_t *r, const mb_anchor_t *a, int bw, int min_match, int32_t *as, int32_t *cnt)
487
+ {
488
+ int32_t i, l, m;
489
+ *as = r->as, *cnt = r->cnt;
490
+ if (r->cnt < 3) return;
491
+ m = l = a[r->as].len;
492
+ for (i = r->as + 1; i < r->as + r->cnt - 1; ++i) {
493
+ int32_t lq, lr, min, max;
494
+ int32_t q_span = a[i].len;
495
+ if (a[i].flag & MB_SEED_LONG_JOIN) break;
496
+ lr = a[i].tpos - a[i-1].tpos;
497
+ lq = a[i].qpos - a[i-1].qpos;
498
+ min = lr < lq? lr : lq;
499
+ max = lr > lq? lr : lq;
500
+ if (max - min > l >> 1) *as = i;
501
+ l += min;
502
+ m += min < q_span? min : q_span;
503
+ if (l >= bw << 1 || (m >= min_match && m >= bw) || m >= r->mlen >> 1) break;
504
+ }
505
+ *cnt = r->as + r->cnt - *as;
506
+ m = l = a[r->as + r->cnt - 1].len;
507
+ for (i = r->as + r->cnt - 2; i > *as; --i) {
508
+ int32_t lq, lr, min, max;
509
+ int32_t q_span = a[i].len;
510
+ if (a[i+1].flag & MB_SEED_LONG_JOIN) break;
511
+ lr = a[i+1].tpos - a[i].tpos - a[i+1].len + a[i].len;
512
+ lq = a[i+1].qpos - a[i].qpos - a[i+1].len + a[i].len;
513
+ min = lr < lq? lr : lq;
514
+ max = lr > lq? lr : lq;
515
+ if (max - min > l >> 1) *cnt = i + 1 - *as;
516
+ l += min;
517
+ m += min < q_span? min : q_span;
518
+ if (l >= bw << 1 || (m >= min_match && m >= bw) || m >= r->mlen >> 1) break;
519
+ }
520
+ }
521
+
522
+ static void mb_max_stretch(const mb_hit_t *r, const mb_anchor_t *a, int32_t *as, int32_t *cnt)
523
+ { // find the max ungapped chain
524
+ int32_t i, score, max_score, len, max_i, max_len;
525
+
526
+ *as = r->as, *cnt = r->cnt;
527
+ if (r->cnt < 2) return;
528
+
529
+ max_score = -1, max_i = -1, max_len = 0;
530
+ score = a[r->as].len, len = 1;
531
+ for (i = r->as + 1; i < r->as + r->cnt; ++i) {
532
+ int32_t lr = a[i].tpos - a[i-1].tpos;
533
+ int32_t lq = a[i].qpos - a[i-1].qpos;
534
+ if (lq == lr) { // ungapped
535
+ score += lq < a[i].len? lq : a[i].len; // in theory, "lq > a[i].len" should always stand
536
+ ++len;
537
+ } else { // a gap
538
+ if (score > max_score)
539
+ max_score = score, max_len = len, max_i = i - len;
540
+ score = a[i].len, len = 1;
541
+ }
542
+ }
543
+ if (score > max_score)
544
+ max_score = score, max_len = len, max_i = i - len;
545
+ *as = max_i, *cnt = max_len;
546
+ }
547
+
548
+ static void mb_align1(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, uint8_t *qseq0[2], l2b_meth_t mt, mb_hit_t *r, mb_hit_t *r2, int n_a, mb_anchor_t *a, ksw_extz_t *ez)
549
+ {
550
+ int32_t is_sr, max_back, rev = a[r->as].sid&1, as1, cnt1;
551
+ uint8_t *tseq = 0, *qseq;
552
+ int32_t i, bw, bw_long, dropped = 0, ksw_flag = 0;
553
+ int64_t tid = a[r->as].sid >> 1, l;
554
+ int64_t ts0, te0, ts1, te1, ts, te; // ts0/te0: range of extracted sequence; ts1/te1: range of alignment; ts/te: moving temporary
555
+ int32_t qs0, qe0, qs1, qe1, qs, qe;
556
+ int8_t mat[25];
557
+
558
+ is_sr = mb_is_sr_mode(opt, qlen);
559
+ max_back = is_sr? 0 : 10; // for long reads, allow up to 10bp "edges" from chain ends
560
+ r2->cnt = 0;
561
+ if (r->cnt == 0) return;
562
+ if (r->rev) mt = l2b_meth_rev(mt);
563
+ ksw_gen_nt4_mat(mat, opt->a, opt->b, opt->b_ts, opt->b_ambi, (int)mt);
564
+ bw = (int)(opt->bw * 1.5 + 1.);
565
+ if (!is_sr) {
566
+ bw_long = (int)(opt->bw_long * 1.5 + 1.);
567
+ if (bw_long < bw) bw_long = bw;
568
+ } else bw_long = bw; // disable long gap in the short-read mode
569
+
570
+ if (is_sr) {
571
+ mb_max_stretch(r, a, &as1, &cnt1);
572
+ } else {
573
+ mm_fix_bad_ends(r, a, opt->bw, opt->min_chain_score * 2, &as1, &cnt1);
574
+ mm_filter_bad_seeds(km, as1, cnt1, a, 10, 40, opt->max_gap>>1, 10);
575
+ mm_filter_bad_seeds_alt(km, as1, cnt1, a, 30, opt->max_gap>>1);
576
+ }
577
+ ts = a[as1].tpos + 1 - a[as1].len + mb_min_int32(a[as1].len>>1, max_back);
578
+ qs = a[as1].qpos + 1 - a[as1].len + mb_min_int32(a[as1].len>>1, max_back);
579
+ te = a[as1+cnt1-1].tpos + 1 - mb_min_int32(a[as1+cnt1-1].len>>1, max_back);
580
+ qe = a[as1+cnt1-1].qpos + 1 - mb_min_int32(a[as1+cnt1-1].len>>1, max_back);
581
+ assert(cnt1 > 0);
582
+
583
+ if (kom_dbg_flag & MB_DBG_AN_POS) {
584
+ for (i = 0; i < r->cnt; ++i) {
585
+ int32_t gap = i == 0? 0 : (a[r->as+i].qpos - a[r->as+i-1].qpos) - (a[r->as+i].tpos - a[r->as+i-1].tpos);
586
+ fprintf(stderr, "AF\t%d\t%s\t%ld\t%d\t%d\t%ld\n", r->as, mi->l2b->ctg[tid].name, (long)a[r->as + i].tpos, a[r->as + i].qpos, gap, (long)a[r->as + i].len);
587
+ }
588
+ }
589
+
590
+ /* Look for the start and end of regions to perform DP. This sounds easy
591
+ * but is in fact tricky. Excessively small regions lead to unnecessary
592
+ * clippings and lose alignable sequences. Excessively large regions
593
+ * occasionally lead to large overlaps between two chains and may cause
594
+ * loss of alignments in corner cases. */
595
+ if (is_sr) {
596
+ qs0 = 0, qe0 = qlen;
597
+ l = qs;
598
+ l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
599
+ ts0 = ts - l > 0? ts - l : 0;
600
+ l = qlen - qe;
601
+ l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
602
+ te0 = te + l < mi->l2b->ctg[tid].len? te + l : mi->l2b->ctg[tid].len;
603
+ } else {
604
+ // compute ts0 and qs0
605
+ ts0 = a[r->as].tpos + 1 - a[r->as].len;
606
+ qs0 = a[r->as].qpos + 1 - a[r->as].len;
607
+ if (ts0 < 0) ts0 = 0;
608
+ assert(qs0 >= 0); // this should never happen, or it is logic error
609
+ ts1 = qs1 = 0;
610
+ if (qs > 0 && ts > 0) {
611
+ l = qs < opt->max_gap? qs : opt->max_gap;
612
+ qs1 = qs1 > qs - l? qs1 : qs - l;
613
+ qs0 = qs0 < qs1? qs0 : qs1; // at least include qs0
614
+ l += l * opt->a > opt->q? (l * opt->a - opt->q) / opt->e : 0;
615
+ l = l < opt->max_gap? l : opt->max_gap;
616
+ l = l < ts? l : ts;
617
+ ts1 = ts1 > ts - l? ts1 : ts - l;
618
+ ts0 = ts0 < ts1? ts0 : ts1;
619
+ ts0 = ts0 < ts? ts0 : ts;
620
+ } else ts0 = ts, qs0 = qs;
621
+ // compute te0 and qe0
622
+ te0 = a[r->as + r->cnt - 1].tpos + 1;
623
+ qe0 = a[r->as + r->cnt - 1].qpos + 1;
624
+ te1 = mi->l2b->ctg[tid].len, qe1 = qlen;
625
+ if (qe < qlen && te < mi->l2b->ctg[tid].len) {
626
+ l = qlen - qe < opt->max_gap? qlen - qe : opt->max_gap;
627
+ qe1 = qe1 < qe + l? qe1 : qe + l;
628
+ qe0 = qe0 > qe1? qe0 : qe1; // at least include qe0
629
+ l += l * opt->a > opt->q? (l * opt->a - opt->q) / opt->e : 0;
630
+ l = l < opt->max_gap? l : opt->max_gap;
631
+ l = l < mi->l2b->ctg[tid].len - te? l : mi->l2b->ctg[tid].len - te;
632
+ te1 = te1 < te + l? te1 : te + l;
633
+ te0 = te0 > te1? te0 : te1;
634
+ } else te0 = te, qe0 = qe;
635
+ }
636
+
637
+ assert(te0 > ts0);
638
+ tseq = Kmalloc(km, uint8_t, te0 - ts0);
639
+
640
+ if (qs > 0 && ts > 0) { // left extension; probably the condition can be changed to "qs > qs0 && ts > ts0"
641
+ qseq = &qseq0[rev][qs0];
642
+ l2b_getseq(mi->l2b, tid, ts0, ts, tseq);
643
+ mb_seq_rev(qs - qs0, qseq);
644
+ mb_seq_rev(ts - ts0, tseq);
645
+ mb_align_pair(km, opt, qs - qs0, qseq, ts - ts0, tseq, mat, bw, opt->end_bonus, r->split_inv? opt->zdrop_inv : opt->zdrop, ksw_flag|KSW_EZ_EXTZ_ONLY|KSW_EZ_RIGHT|KSW_EZ_REV_CIGAR, ez);
646
+ if (ez->n_cigar > 0) {
647
+ mb_append_cigar(r, ez->n_cigar, ez->cigar);
648
+ r->p->dp_score += ez->reach_end? ez->mqe : ez->max;
649
+ }
650
+ ts1 = ts - (ez->reach_end? ez->mqe_t + 1 : ez->max_t + 1);
651
+ qs1 = qs - (ez->reach_end? qs - qs0 : ez->max_q + 1);
652
+ mb_seq_rev(qs - qs0, qseq);
653
+ } else ts1 = ts, qs1 = qs;
654
+ te1 = ts, qe1 = qs;
655
+ assert(qs1 >= 0 && ts1 >= 0);
656
+
657
+ { // adding exact match on the first unfiltered anchor
658
+ te = te1 = a[as1].tpos + 1 - mb_min_int32(a[as1].len>>1, max_back);
659
+ qe = qe1 = a[as1].qpos + 1 - mb_min_int32(a[as1].len>>1, max_back);
660
+ assert(te - ts == qe - qs && te >= ts);
661
+ uint32_t cigar0 = (te - ts) << 4 | MB_CIGAR_MATCH;
662
+ mb_append_cigar(r, 1, &cigar0);
663
+ r->p->dp_score += opt->a * (te - ts);
664
+ ts = te, qs = qe;
665
+ }
666
+
667
+ for (i = 1; i < cnt1; ++i) { // gap filling
668
+ const mb_anchor_t *ai = &a[as1 + i];
669
+ if ((ai->flag & MB_SEED_IGNORE) && i != cnt1 - 1) continue;
670
+ te1 = ai->tpos + 1 - mb_min_int32(ai->len>>1, max_back);
671
+ qe1 = ai->qpos + 1 - mb_min_int32(ai->len>>1, max_back);
672
+ if (i == cnt1 - 1 || (a[as1+i].flag&MB_SEED_LONG_JOIN) || (qe1 - qs >= opt->min_ksw_len && te1 - ts >= opt->min_ksw_len)) { // gap filling
673
+ int32_t j, bw1 = bw_long, zdrop_code;
674
+ int64_t d1 = 0; // distance from (qe1,te1) to trim
675
+ // compute ts and te
676
+ if (ai->len > opt->min_len * 2) {
677
+ d1 = te1 - (ai->tpos + 1 - ai->len); // distance to the start of the anchor
678
+ d1 = d1 < qe1 - qs? d1 : qe1 - qs;
679
+ d1 = d1 < te1 - ts? d1 : te1 - ts;
680
+ d1 -= opt->min_len;
681
+ if (d1 < opt->min_len) d1 = 0;
682
+ }
683
+ te = te1 - d1, qe = qe1 - d1;
684
+ // update bandwidth
685
+ if (a[as1+i].flag & MB_SEED_LONG_JOIN)
686
+ bw1 = qe - qs > te - ts? qe - qs : te - ts;
687
+ // perform alignment
688
+ qseq = &qseq0[rev][qs];
689
+ l2b_getseq(mi->l2b, tid, ts, te, tseq);
690
+ mb_align_pair(km, opt, qe - qs, qseq, te - ts, tseq, mat, bw1, -1, opt->zdrop, ksw_flag|KSW_EZ_APPROX_MAX, ez); // first pass: with approximate Z-drop
691
+ // test Z-drop and inversion Z-drop
692
+ if ((zdrop_code = mm_test_zdrop(km, opt, qseq, tseq, ez->n_cigar, ez->cigar, mat, is_sr)) != 0)
693
+ mb_align_pair(km, opt, qe - qs, qseq, te - ts, tseq, mat, bw1, -1, zdrop_code == 2? opt->zdrop_inv : opt->zdrop, ksw_flag, ez); // second pass: lift approximate
694
+ if (kom_dbg_flag & MB_DBG_AN_POS) fprintf(stderr, "AD\t%d\t%ld\t%ld\t%d\t%d\t%d\t%d\n", r->as, (long)ts, (long)te, qs, qe, zdrop_code, ez->zdropped);
695
+ // update CIGAR
696
+ if (ez->n_cigar > 0)
697
+ mb_append_cigar(r, ez->n_cigar, ez->cigar);
698
+ if (ez->zdropped) { // truncated by Z-drop; TODO: sometimes Z-drop kicks in because the next seed placement is wrong. This can be fixed in principle.
699
+ int32_t mlen, blen;
700
+ if (!r->p) {
701
+ assert(ez->n_cigar == 0);
702
+ uint32_t cap = sizeof(mb_extra_t)/4;
703
+ kom_roundup32(cap);
704
+ r->p = (mb_extra_t*)calloc(cap, 4);
705
+ r->p->cap = cap;
706
+ }
707
+ for (j = i - 1; j >= 0; --j)
708
+ if (a[as1 + j].tpos <= ts + ez->max_t)
709
+ break;
710
+ dropped = 1;
711
+ if (j < 0) j = 0;
712
+ r->p->dp_score += ez->max;
713
+ te1 = ts + (ez->max_t + 1);
714
+ qe1 = qs + (ez->max_q + 1);
715
+ mlen = mb_cal_mblen(cnt1 - (j + 1), &a[as1 + j + 1], &blen);
716
+ if (mlen >= opt->min_chain_score) { // TODO: check if this is correct
717
+ mb_split_hit(r, r2, as1 + j + 1 - r->as, qlen, a, mi->l2b);
718
+ if (zdrop_code == 2) r2->split_inv = 1;
719
+ }
720
+ break;
721
+ } else r->p->dp_score += ez->score;
722
+ if (d1 > 0) {
723
+ uint32_t cigar0 = d1 << 4 | MB_CIGAR_MATCH;
724
+ mb_append_cigar(r, 1, &cigar0);
725
+ r->p->dp_score += opt->a * d1;
726
+ te = te1, qe = qe1;
727
+ }
728
+ ts = te, qs = qe;
729
+ }
730
+ }
731
+
732
+ if (!dropped && qe < qe0 && te < te0) { // right extension
733
+ qseq = &qseq0[rev][qe];
734
+ l2b_getseq(mi->l2b, tid, te, te0, tseq);
735
+ mb_align_pair(km, opt, qe0 - qe, qseq, te0 - te, tseq, mat, bw, opt->end_bonus, opt->zdrop, ksw_flag|KSW_EZ_EXTZ_ONLY, ez);
736
+ if (ez->n_cigar > 0) {
737
+ mb_append_cigar(r, ez->n_cigar, ez->cigar);
738
+ r->p->dp_score += ez->reach_end? ez->mqe : ez->max;
739
+ }
740
+ te1 = te + (ez->reach_end? ez->mqe_t + 1 : ez->max_t + 1);
741
+ qe1 = qe + (ez->reach_end? qe0 - qe : ez->max_q + 1);
742
+ }
743
+ assert(qe1 <= qlen);
744
+
745
+ r->ts = ts1, r->te = te1;
746
+ if (!rev) r->qs = qs1, r->qe = qe1;
747
+ else r->qs = qlen - qe1, r->qe = qlen - qs1;
748
+
749
+ assert(te1 - ts1 <= te0 - ts0);
750
+ if (r->p) {
751
+ l2b_getseq(mi->l2b, tid, ts1, te1, tseq);
752
+ qseq = &qseq0[r->rev][qs1];
753
+ mb_update_extra(km, r, qseq, tseq, mat, opt->q, opt->e, opt->flag, !is_sr);
754
+ }
755
+
756
+ kfree(km, tseq);
757
+ }
758
+
759
+ static int mb_align1_inv(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, uint8_t *qseq0[2], l2b_meth_t mt, const mb_hit_t *r1, const mb_hit_t *r2, mb_hit_t *r_inv, ksw_extz_t *ez)
760
+ { // NB: this doesn't work with the qstrand mode
761
+ int tl, ql, score, ret = 0, q_off, t_off;
762
+ uint8_t *tseq, *qseq;
763
+ int8_t mat[25];
764
+ void *qp;
765
+
766
+ memset(r_inv, 0, sizeof(mb_hit_t));
767
+ if (!(r1->split&1) || !(r2->split&2)) return 0;
768
+ if (r1->id != r1->parent && r1->parent != MB_PARENT_TMP_PRI) return 0;
769
+ if (r2->id != r2->parent && r2->parent != MB_PARENT_TMP_PRI) return 0;
770
+ if (r1->tid != r2->tid || r1->rev != r2->rev) return 0;
771
+ ql = r1->rev? r1->qs - r2->qe : r2->qs - r1->qe;
772
+ tl = r2->ts - r1->te;
773
+ if (ql < opt->min_chain_score || ql > opt->max_gap) return 0;
774
+ if (tl < opt->min_chain_score || tl > opt->max_gap) return 0;
775
+
776
+ if (!r1->rev) mt = l2b_meth_rev(mt); // TODO: check if this is correct
777
+ ksw_gen_nt4_mat(mat, opt->a, opt->b, opt->b_ts, opt->b_ambi, (int)mt);
778
+
779
+ tseq = (uint8_t*)kmalloc(km, tl);
780
+ l2b_getseq(mi->l2b, r1->tid, r1->te, r2->ts, tseq);
781
+ qseq = r1->rev? &qseq0[0][r2->qe] : &qseq0[1][qlen - r2->qs];
782
+
783
+ mb_seq_rev(ql, qseq);
784
+ mb_seq_rev(tl, tseq);
785
+ qp = ksw_ll_qinit(km, 2, ql, qseq, 5, mat);
786
+ score = ksw_ll_i16(qp, tl, tseq, opt->q, opt->e, &q_off, &t_off);
787
+ kfree(km, qp);
788
+ mb_seq_rev(ql, qseq);
789
+ mb_seq_rev(tl, tseq);
790
+ if (score < opt->min_dp_max * opt->a) goto end_align1_inv;
791
+ q_off = ql - (q_off + 1), t_off = tl - (t_off + 1);
792
+ mb_align_pair(km, opt, ql - q_off, qseq + q_off, tl - t_off, tseq + t_off, mat, (int)(opt->bw * 1.5), -1, opt->zdrop, KSW_EZ_EXTZ_ONLY, ez);
793
+ if (ez->n_cigar == 0) goto end_align1_inv; // should never be here
794
+ mb_append_cigar(r_inv, ez->n_cigar, ez->cigar);
795
+ r_inv->p->dp_score = ez->max;
796
+ r_inv->id = -1;
797
+ r_inv->parent = MB_PARENT_UNSET;
798
+ r_inv->inv = 1;
799
+ r_inv->rev = !r1->rev;
800
+ r_inv->tid = r1->tid;
801
+ if (r_inv->rev == 0) {
802
+ r_inv->qs = r2->qe + q_off;
803
+ r_inv->qe = r_inv->qs + ez->max_q + 1;
804
+ } else {
805
+ r_inv->qe = r2->qs - q_off;
806
+ r_inv->qs = r_inv->qe - (ez->max_q + 1);
807
+ }
808
+ r_inv->ts = r1->te + t_off;
809
+ r_inv->te = r_inv->ts + ez->max_t + 1;
810
+ mb_update_extra(km, r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e, opt->flag, mb_is_sr_mode(opt, qlen));
811
+ ret = 1;
812
+ end_align1_inv:
813
+ kfree(km, tseq);
814
+ return ret;
815
+ }
816
+
817
+ static inline mb_hit_t *mb_insert_reg(const mb_hit_t *r, int i, int *n_regs, mb_hit_t *regs)
818
+ {
819
+ regs = (mb_hit_t*)realloc(regs, (*n_regs + 1) * sizeof(mb_hit_t));
820
+ if (i + 1 != *n_regs)
821
+ memmove(&regs[i + 2], &regs[i + 1], sizeof(mb_hit_t) * (*n_regs - i - 1));
822
+ regs[i + 1] = *r;
823
+ ++*n_regs;
824
+ return regs;
825
+ }
826
+
827
+ static inline void mb_count_gaps(const mb_hit_t *r, int32_t *n_gap_, int32_t *n_gapo_)
828
+ {
829
+ uint32_t i;
830
+ int32_t n_gapo = 0, n_gap = 0;
831
+ *n_gap_ = *n_gapo_ = -1;
832
+ if (r->p == 0) return;
833
+ for (i = 0; i < r->p->n_cigar; ++i) {
834
+ int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
835
+ if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL)
836
+ ++n_gapo, n_gap += len;
837
+ }
838
+ *n_gap_ = n_gap, *n_gapo_ = n_gapo;
839
+ }
840
+
841
+ static double mb_event_identity(const mb_hit_t *r)
842
+ {
843
+ int32_t n_gap, n_gapo;
844
+ if (r->p == 0) return -1.0f;
845
+ mb_count_gaps(r, &n_gap, &n_gapo);
846
+ return (double)r->mlen / (r->blen + r->p->n_ambi - n_gap + n_gapo);
847
+ }
848
+
849
+ static int32_t mb_recal_max_dp(const mb_hit_t *r, double b2, int32_t match_sc, int32_t qlen)
850
+ {
851
+ uint32_t i;
852
+ int32_t n_gap = 0, n_mis;
853
+ double gap_cost = 0.0;
854
+ if (r->p == 0) return -1;
855
+ for (i = 0; i < r->p->n_cigar; ++i) {
856
+ int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
857
+ if (op == MB_CIGAR_INS || op == MB_CIGAR_DEL) {
858
+ gap_cost += b2 * mb_log2(1.0 + len);
859
+ n_gap += len;
860
+ }
861
+ }
862
+ n_mis = r->blen + r->p->n_ambi - r->mlen - n_gap;
863
+ n_mis += (int32_t)((qlen - (r->qe - r->qs)) / b2 + .499);
864
+ return (int32_t)(match_sc * (r->mlen - b2 * n_mis - gap_cost) + .499);
865
+ }
866
+
867
+ void mb_update_dp_max(int qlen, int n_regs, mb_hit_t *regs, double frac, int a, int b)
868
+ {
869
+ int32_t max = -1, max2 = -1, i, max_i = -1, max2_i = -1;
870
+ double div, b2;
871
+ if (n_regs < 2) return;
872
+ for (i = 0; i < n_regs; ++i) {
873
+ mb_hit_t *r = &regs[i];
874
+ if (r->p == 0) continue;
875
+ if (r->p->dp_max > max) max2 = max, max2_i = max_i, max = r->p->dp_max, max_i = i;
876
+ else if (r->p->dp_max > max2) max2 = r->p->dp_max, max2_i = i;
877
+ }
878
+ if (max_i < 0 || max2_i < 0) return;
879
+ if (regs[max_i].qe - regs[max_i].qs < qlen * frac) return;
880
+ if (regs[max2_i].qe - regs[max2_i].qs < (regs[max_i].qe - regs[max_i].qs) * sqrt(frac)) return;
881
+ div = 1. - mb_event_identity(&regs[max_i]);
882
+ if (div < 0.02) div = 0.02;
883
+ b2 = 0.5 / div; // max value: 25
884
+ if (b2 * a < b) b2 = (double)a / b;
885
+ for (i = 0, max = -1, max_i = -1; i < n_regs; ++i) {
886
+ mb_hit_t *r = &regs[i];
887
+ if (r->p == 0) continue;
888
+ r->p->dp_max = mb_recal_max_dp(r, b2, a, qlen);
889
+ if (r->p->dp_max < 0) r->p->dp_max = 0;
890
+ if (max < r->p->dp_max) max = r->p->dp_max, max_i = i;
891
+ }
892
+ }
893
+
894
+ mb_hit_t *mb_align_skeleton(void *km, const mb_opt_t *opt, const mb_idx_t *mi, int qlen, const uint8_t *qseq, l2b_meth_t mt, int *n_regs_, mb_hit_t *regs, mb_anchor_t *a)
895
+ {
896
+ int32_t i, n_regs = *n_regs_, n_a;
897
+ uint8_t *qseq0[2];
898
+ ksw_extz_t ez;
899
+
900
+ // encode the query sequence
901
+ qseq0[0] = Kmalloc(km, uint8_t, qlen * 2);
902
+ qseq0[1] = qseq0[0] + qlen;
903
+ for (i = 0; i < qlen; ++i)
904
+ qseq0[0][i] = qseq[i], qseq0[1][qlen - 1 - i] = qseq0[0][i] < 4? 3 - qseq0[0][i] : 4;
905
+
906
+ // align through seed hits
907
+ n_a = mb_squeeze_a(km, n_regs, regs, a);
908
+ memset(&ez, 0, sizeof(ksw_extz_t));
909
+ for (i = 0; i < n_regs; ++i) {
910
+ mb_hit_t r2; // only used for inversion
911
+ mb_align1(km, opt, mi, qlen, qseq0, mt, &regs[i], &r2, n_a, a, &ez);
912
+ if (r2.cnt > 0) regs = mb_insert_reg(&r2, i, &n_regs, regs);
913
+ if (i > 0 && regs[i].split_inv) {
914
+ if (mb_align1_inv(km, opt, mi, qlen, qseq0, mt, &regs[i-1], &regs[i], &r2, &ez)) {
915
+ regs = mb_insert_reg(&r2, i, &n_regs, regs);
916
+ ++i; // skip the inserted INV alignment
917
+ }
918
+ }
919
+ }
920
+ kfree(km, qseq0[0]);
921
+ kfree(km, ez.cigar);
922
+ mb_filter_hits(opt, qlen, &n_regs, regs);
923
+ if (!mb_is_sr_mode(opt, qlen)) {
924
+ mb_update_dp_max(qlen, n_regs, regs, 0.9, opt->a, opt->b);
925
+ mb_filter_hits(opt, qlen, &n_regs, regs);
926
+ }
927
+ mb_hit_sort(km, &n_regs, regs);
928
+ *n_regs_ = n_regs;
929
+ return regs;
930
+ }