Compare commits

...
24 Commits
Author SHA1 Message Date
Heng Li fe35e679e9 Release minimap2-2.24 (r1122) 2021-12-26 15:14:54 -05:00
Heng Li e25aa5ee74 r1121: change bw_long to bw if bw is longer
Resolve #852
2021-12-26 14:37:31 -05:00
Heng Li 3bde3450a0 r1121: updated obsolete settings in manpage
Resolve #851
2021-12-26 14:33:14 -05:00
Heng Li 36942ff711 r1119: fixed a typo in the new chaining code
Not affecting v2.23
2021-12-25 12:46:26 -05:00
Heng Li d3a89d34d4 r1118: use -r1k,100k for asm* modes 2021-12-23 20:43:54 -05:00
Heng Li c8f0a35c40 r1117: added --no-hash-name for deterministic 2021-11-24 16:49:48 -05:00
Heng Li fcaadc22b7 r1116: cut long chains at weak points 2021-11-20 19:07:44 -05:00
Heng Li db37fc43a7 r1115: prepare for chain breaking 2021-11-20 13:42:44 -05:00
Heng Li a8f1fa8ea3 r1114: retain more candidate inversion alignments 2021-11-18 21:37:10 -05:00
Heng Li b276772890 r1112: added --print-chains for debugging 2021-11-18 21:26:41 -05:00
Heng Li d0cff3eb36 Release minimap2-2.23 (r1111) 2021-11-18 17:11:48 -05:00
Heng Li ac334639ce r1110: default --cap-kalloc=1g; test more inv
See #816 and #823
2021-10-11 14:45:15 -04:00
Heng Li 546623dcb4 r1109: disable chain_skip_scale by default
Enabling the option slows down alignment, possibly because it fragments chains
in difficult regions.
2021-10-04 21:24:35 -04:00
Heng Li 39bdd45875 r1108: fixed missing inversions for #816 and #806 2021-10-04 16:34:30 -04:00
Heng Li aefa2c0d86 added --chain-skip-scale 2021-10-01 16:58:03 -04:00
Heng Li 7ee62dae1d updated manuscript 2021-10-01 11:42:36 -04:00
Heng Li 05a8a45d44 r1105: avoid long running time occasionally (#771)
Caused by highly repetitive minimizers on a query sequence. The solution is to
filter out these query minimizers.
2021-08-15 19:43:01 -04:00
Heng Li cc14d1afdf fixed typos 2021-08-08 11:18:02 -04:00
Heng Li bb3048b2a0 removed one extra sentence 2021-08-07 16:55:02 -04:00
Heng Li 5113ca2628 improved manuscript 2021-08-07 16:01:15 -04:00
Heng Li 7358a1ead1 Release minimap2-2.22 (r1101) 2021-08-07 11:30:31 -04:00
Heng Li 32f552957e Merge remote-tracking branch 'remotes/origin/master' 2021-08-07 10:40:02 -04:00
Ryan Lim 59488f0271 call mm_idx_destroy at the end of loop to fix memory leak 2021-07-26 18:25:08 -04:00
Jason Stajich 5cc3d2239f missing target object files from Makefile.simde to fix issue #779 2021-07-07 23:07:27 -04:00
19 changed files with 320 additions and 103 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra
CPPFLAGS= -DHAVE_KALLOC -DUSE_SIMDE -DSIMDE_ENABLE_NATIVE_ALIASES CPPFLAGS= -DHAVE_KALLOC -DUSE_SIMDE -DSIMDE_ENABLE_NATIVE_ALIASES
INCLUDES= -Ilib/simde INCLUDES= -Ilib/simde
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o options.o index.o chain.o align.o hit.o map.o format.o pe.o esterr.o splitidx.o \ OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o options.o index.o lchain.o align.o hit.o map.o format.o pe.o seed.o esterr.o splitidx.o \
ksw2_extz2_simde.o ksw2_extd2_simde.o ksw2_exts2_simde.o ksw2_ll_simde.o ksw2_extz2_simde.o ksw2_extd2_simde.o ksw2_exts2_simde.o ksw2_ll_simde.o
PROG= minimap2 PROG= minimap2
PROG_EXTRA= sdust minimap2-lite PROG_EXTRA= sdust minimap2-lite
+58 -1
View File
@@ -1,3 +1,60 @@
Release 2.24-r1122 (26 December 2021)
-------------------------------------
This release improves alignment around long poorly aligned regions. Older
minimap2 may chain through such regions in rare cases which may result in
missing alignments later. The issue has become worse since the the change of
the chaining algorithm in v2.19. v2.23 implements an incomplete remedy. This
release provides a better solution with a X-drop-like heuristic and by enabling
two-bandwidth chaining in the assembly mode.
(2.24: 26 December 2021, r1122)
Release 2.23-r1111 (18 November 2021)
-------------------------------------
Notable changes:
* Bugfix: fixed missing alignments around long inversions (#806 and #816).
This bug affected v2.19 through v2.22.
* Improvement: avoid extremely long mapping time for pathologic reads with
highly repeated k-mers not in the reference (#771). Use --q-occ-frac=0
to disable the new heuristic.
* Change: use --cap-kalloc=1g by default.
(2.23: 18 November 2021, r1111)
Release 2.22-r1101 (7 August 2021)
----------------------------------
When choosing the best alignment, this release uses logarithm gap penalty and
query-specific mismatch penalty. It improves the sensitivity to long INDELs in
repetitive regions.
Other notable changes:
* Bugfix: fixed an indirect memory leak that may waste a large amount of
memory given highly repetitive reference such as a 16S RNA database (#749).
All versions of minimap2 have this issue.
* New feature: added --cap-kalloc to reduce the peak memory. This option is
not enabled by default but may become the default in future releases.
Known issue:
* Minimap2 may take a long time to map a read (#771). So far it is not clear
if this happens to v2.18 and earlier versions.
(2.22: 7 August 2021, r1101)
Release 2.21-r1071 (6 July 2021) Release 2.21-r1071 (6 July 2021)
-------------------------------- --------------------------------
@@ -5,7 +62,7 @@ This release fixed a regression in short-read mapping introduced in v2.19
(#776). It also fixed invalid comparisons of uninitialized variables, though (#776). It also fixed invalid comparisons of uninitialized variables, though
these are harmless (#752). Long-read alignment should be identical to v2.20. these are harmless (#752). Long-read alignment should be identical to v2.20.
(2.21: 6 July 2021) (2.21: 6 July 2021, r1071)
+2 -2
View File
@@ -74,8 +74,8 @@ Detailed evaluations are available from the [minimap2 paper][doi] or the
Minimap2 is optimized for x86-64 CPUs. You can acquire precompiled binaries from Minimap2 is optimized for x86-64 CPUs. You can acquire precompiled binaries from
the [release page][release] with: the [release page][release] with:
```sh ```sh
curl -L https://github.com/lh3/minimap2/releases/download/v2.21/minimap2-2.21_x64-linux.tar.bz2 | tar -jxvf - curl -L https://github.com/lh3/minimap2/releases/download/v2.24/minimap2-2.24_x64-linux.tar.bz2 | tar -jxvf -
./minimap2-2.21_x64-linux/minimap2 ./minimap2-2.24_x64-linux/minimap2
``` ```
If you want to compile from the source, you need to have a C compiler, GNU make If you want to compile from the source, you need to have a C compiler, GNU make
and zlib development files installed. Then type `make` in the source code and zlib development files installed. Then type `make` in the source code
+2 -2
View File
@@ -31,8 +31,8 @@ To acquire the data used in this cookbook and to install minimap2 and paftools,
please follow the command lines below: please follow the command lines below:
```sh ```sh
# install minimap2 executables # install minimap2 executables
curl -L https://github.com/lh3/minimap2/releases/download/v2.21/minimap2-2.21_x64-linux.tar.bz2 | tar jxf - curl -L https://github.com/lh3/minimap2/releases/download/v2.24/minimap2-2.24_x64-linux.tar.bz2 | tar jxf -
cp minimap2-2.21_x64-linux/{minimap2,k8,paftools.js} . # copy executables cp minimap2-2.24_x64-linux/{minimap2,k8,paftools.js} . # copy executables
export PATH="$PATH:"`pwd` # put the current directory on PATH export PATH="$PATH:"`pwd` # put the current directory on PATH
# download example datasets # download example datasets
curl -L https://github.com/lh3/minimap2/releases/download/v2.10/cookbook-data.tgz | tar zxf - curl -L https://github.com/lh3/minimap2/releases/download/v2.10/cookbook-data.tgz | tar zxf -
+17 -1
View File
@@ -252,7 +252,7 @@ void mm_sync_regs(void *km, int n_regs, mm_reg1_t *regs) // keep mm_reg1_t::{id,
mm_set_sam_pri(n_regs, regs); mm_set_sam_pri(n_regs, regs);
} }
void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_, mm_reg1_t *r) void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int check_strand, int min_strand_sc, int *n_, mm_reg1_t *r)
{ {
if (pri_ratio > 0.0f && *n_ > 0) { if (pri_ratio > 0.0f && *n_ > 0) {
int i, k, n = *n_, n_2nd = 0; int i, k, n = *n_, n_2nd = 0;
@@ -264,6 +264,9 @@ void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_,
if (!(r[i].qs == r[p].qs && r[i].qe == r[p].qe && r[i].rid == r[p].rid && r[i].rs == r[p].rs && r[i].re == r[p].re)) // not identical hits if (!(r[i].qs == r[p].qs && r[i].qe == r[p].qe && r[i].rid == r[p].rid && r[i].rs == r[p].rs && r[i].re == r[p].re)) // not identical hits
r[k++] = r[i], ++n_2nd; r[k++] = r[i], ++n_2nd;
else if (r[i].p) free(r[i].p); else if (r[i].p) free(r[i].p);
} else if (check_strand && n_2nd < best_n && r[i].score > min_strand_sc && r[i].rev != r[p].rev) {
r[i].strand_retained = 1;
r[k++] = r[i], ++n_2nd;
} else if (r[i].p) free(r[i].p); } else if (r[i].p) free(r[i].p);
} }
if (k != n) mm_sync_regs(km, k, r); // removing hits requires sync() if (k != n) mm_sync_regs(km, k, r); // removing hits requires sync()
@@ -271,6 +274,19 @@ void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_,
} }
} }
int mm_filter_strand_retained(int n_regs, mm_reg1_t *r)
{
int i, k;
for (i = k = 0; i < n_regs; ++i) {
int p = r[i].parent;
if (!r[i].strand_retained || r[i].div < r[p].div * 5.0f || r[i].div < 0.01f) {
if (k < i) r[k++] = r[i];
else ++k;
}
}
return k;
}
void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs) void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs)
{ // NB: after this call, mm_reg1_t::parent can be -1 if its parent filtered out { // NB: after this call, mm_reg1_t::parent can be -1 if its parent filtered out
int i, k; int i, k;
+34 -9
View File
@@ -6,7 +6,25 @@
#include "kalloc.h" #include "kalloc.h"
#include "krmq.h" #include "krmq.h"
uint64_t *mg_chain_backtrack(void *km, int64_t n, const int32_t *f, const int64_t *p, int32_t *v, int32_t *t, int32_t min_cnt, int32_t min_sc, int32_t *n_u_, int32_t *n_v_) static int64_t mg_chain_bk_end(int32_t max_drop, const mm128_t *z, const int32_t *f, const int64_t *p, int32_t *t, int64_t k)
{
int64_t i = z[k].y, end_i = -1, max_i = i;
int32_t max_s = 0;
if (i < 0 || t[i] != 0) return i;
do {
int32_t s;
t[i] = 2;
end_i = i = p[i];
s = i < 0? z[k].x : (int32_t)z[k].x - f[i];
if (s > max_s) max_s = s, max_i = i;
else if (max_s - s > max_drop) break;
} while (i >= 0 && t[i] == 0);
for (i = z[k].y; i >= 0 && i != end_i; i = p[i]) // reset modified t[]
t[i] = 0;
return max_i;
}
uint64_t *mg_chain_backtrack(void *km, int64_t n, const int32_t *f, const int64_t *p, int32_t *v, int32_t *t, int32_t min_cnt, int32_t min_sc, int32_t max_drop, int32_t *n_u_, int32_t *n_v_)
{ {
mm128_t *z; mm128_t *z;
uint64_t *u; uint64_t *u;
@@ -24,27 +42,33 @@ uint64_t *mg_chain_backtrack(void *km, int64_t n, const int32_t *f, const int64_
memset(t, 0, n * 4); memset(t, 0, n * 4);
for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // precompute n_u for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // precompute n_u
int64_t n_v0 = n_v; if (t[z[k].y] == 0) {
int64_t n_v0 = n_v, end_i;
int32_t sc; int32_t sc;
for (i = z[k].y; i >= 0 && t[i] == 0; i = p[i]) end_i = mg_chain_bk_end(max_drop, z, f, p, t, k);
for (i = z[k].y; i != end_i; i = p[i])
++n_v, t[i] = 1; ++n_v, t[i] = 1;
sc = i < 0? z[k].x : (int32_t)z[k].x - f[i]; sc = i < 0? z[k].x : (int32_t)z[k].x - f[i];
if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt) if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt)
++n_u; ++n_u;
else n_v = n_v0; else n_v = n_v0;
} }
}
KMALLOC(km, u, n_u); KMALLOC(km, u, n_u);
memset(t, 0, n * 4); memset(t, 0, n * 4);
for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // populate u[] for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // populate u[]
int64_t n_v0 = n_v; if (t[z[k].y] == 0) {
int64_t n_v0 = n_v, end_i;
int32_t sc; int32_t sc;
for (i = z[k].y; i >= 0 && t[i] == 0; i = p[i]) end_i = mg_chain_bk_end(max_drop, z, f, p, t, k);
for (i = z[k].y; i != end_i; i = p[i])
v[n_v++] = i, t[i] = 1; v[n_v++] = i, t[i] = 1;
sc = i < 0? z[k].x : (int32_t)z[k].x - f[i]; sc = i < 0? z[k].x : (int32_t)z[k].x - f[i];
if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt) if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt)
u[n_u++] = (uint64_t)sc << 32 | (n_v - n_v0); u[n_u++] = (uint64_t)sc << 32 | (n_v - n_v0);
else n_v = n_v0; else n_v = n_v0;
} }
}
kfree(km, z); kfree(km, z);
assert(n_v < INT32_MAX); assert(n_v < INT32_MAX);
*n_u_ = n_u, *n_v_ = n_v; *n_u_ = n_u, *n_v_ = n_v;
@@ -124,7 +148,7 @@ static inline int32_t comput_sc(const mm128_t *ai, const mm128_t *aj, int32_t ma
mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int max_iter, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip, mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int max_iter, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
int is_cdna, int n_seg, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km) int is_cdna, int n_seg, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km)
{ // TODO: make sure this works when n has more than 32 bits { // TODO: make sure this works when n has more than 32 bits
int32_t *f, *t, *v, n_u, n_v, mmax_f = 0; int32_t *f, *t, *v, n_u, n_v, mmax_f = 0, max_drop = bw;
int64_t *p, i, j, max_ii, st = 0, n_iter = 0; int64_t *p, i, j, max_ii, st = 0, n_iter = 0;
uint64_t *u; uint64_t *u;
@@ -135,6 +159,7 @@ mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int
} }
if (max_dist_x < bw) max_dist_x = bw; if (max_dist_x < bw) max_dist_x = bw;
if (max_dist_y < bw && !is_cdna) max_dist_y = bw; if (max_dist_y < bw && !is_cdna) max_dist_y = bw;
if (is_cdna) max_drop = INT32_MAX;
KMALLOC(km, p, n); KMALLOC(km, p, n);
KMALLOC(km, f, n); KMALLOC(km, f, n);
KMALLOC(km, v, n); KMALLOC(km, v, n);
@@ -181,7 +206,7 @@ mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int
if (mmax_f < max_f) mmax_f = max_f; if (mmax_f < max_f) mmax_f = max_f;
} }
u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, &n_u, &n_v); u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, max_drop, &n_u, &n_v);
*n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here *n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here
kfree(km, p); kfree(km, f); kfree(km, t); kfree(km, p); kfree(km, f); kfree(km, t);
if (n_u == 0) { if (n_u == 0) {
@@ -225,7 +250,7 @@ static inline int32_t comput_sc_simple(const mm128_t *ai, const mm128_t *aj, flo
mm128_t *mg_lchain_rmq(int max_dist, int max_dist_inner, int bw, int max_chn_skip, int cap_rmq_size, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip, mm128_t *mg_lchain_rmq(int max_dist, int max_dist_inner, int bw, int max_chn_skip, int cap_rmq_size, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km) int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km)
{ {
int32_t *f,*t, *v, n_u, n_v, mmax_f = 0, max_rmq_size = 0; int32_t *f,*t, *v, n_u, n_v, mmax_f = 0, max_rmq_size = 0, max_drop = bw;
int64_t *p, i, i0, st = 0, st_inner = 0, n_iter = 0; int64_t *p, i, i0, st = 0, st_inner = 0, n_iter = 0;
uint64_t *u; uint64_t *u;
lc_elem_t *root = 0, *root_inner = 0; lc_elem_t *root = 0, *root_inner = 0;
@@ -333,7 +358,7 @@ mm128_t *mg_lchain_rmq(int max_dist, int max_dist_inner, int bw, int max_chn_ski
} }
km_destroy(mem_mp); km_destroy(mem_mp);
u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, &n_u, &n_v); u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, max_drop, &n_u, &n_v);
*n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here *n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here
kfree(km, p); kfree(km, f); kfree(km, t); kfree(km, p); kfree(km, f); kfree(km, t);
if (n_u == 0) { if (n_u == 0) {
+13 -2
View File
@@ -7,7 +7,7 @@
#include "mmpriv.h" #include "mmpriv.h"
#include "ketopt.h" #include "ketopt.h"
#define MM_VERSION "2.21-dev-r1094-dirty" #define MM_VERSION "2.24-r1122"
#ifdef __linux__ #ifdef __linux__
#include <sys/resource.h> #include <sys/resource.h>
@@ -74,6 +74,10 @@ static ko_longopt_t long_options[] = {
{ "rmq", ko_optional_argument, 347 }, { "rmq", ko_optional_argument, 347 },
{ "qstrand", ko_no_argument, 348 }, { "qstrand", ko_no_argument, 348 },
{ "cap-kalloc", ko_required_argument, 349 }, { "cap-kalloc", ko_required_argument, 349 },
{ "q-occ-frac", ko_required_argument, 350 },
{ "chain-skip-scale",ko_required_argument,351 },
{ "print-chains", ko_no_argument, 352 },
{ "no-hash-name", ko_no_argument, 353 },
{ "help", ko_no_argument, 'h' }, { "help", ko_no_argument, 'h' },
{ "max-intron-len", ko_required_argument, 'G' }, { "max-intron-len", ko_required_argument, 'G' },
{ "version", ko_no_argument, 'V' }, { "version", ko_no_argument, 'V' },
@@ -224,11 +228,15 @@ int main(int argc, char *argv[])
else if (c == 341) opt.junc_bonus = atoi(o.arg); // --junc-bonus else if (c == 341) opt.junc_bonus = atoi(o.arg); // --junc-bonus
else if (c == 342) opt.flag |= MM_F_SAM_HIT_ONLY; // --sam-hit-only else if (c == 342) opt.flag |= MM_F_SAM_HIT_ONLY; // --sam-hit-only
else if (c == 343) opt.chain_gap_scale = atof(o.arg); // --chain-gap-scale else if (c == 343) opt.chain_gap_scale = atof(o.arg); // --chain-gap-scale
else if (c == 351) opt.chain_skip_scale = atof(o.arg); // --chain-skip-scale
else if (c == 344) alt_list = o.arg; // --alt else if (c == 344) alt_list = o.arg; // --alt
else if (c == 345) opt.alt_drop = atof(o.arg); // --alt-drop else if (c == 345) opt.alt_drop = atof(o.arg); // --alt-drop
else if (c == 346) opt.mask_len = mm_parse_num(o.arg); // --mask-len else if (c == 346) opt.mask_len = mm_parse_num(o.arg); // --mask-len
else if (c == 348) opt.flag |= MM_F_QSTRAND | MM_F_NO_INV; // --qstrand else if (c == 348) opt.flag |= MM_F_QSTRAND | MM_F_NO_INV; // --qstrand
else if (c == 349) opt.cap_kalloc = mm_parse_num(o.arg); // --cap-kalloc else if (c == 349) opt.cap_kalloc = mm_parse_num(o.arg); // --cap-kalloc
else if (c == 350) opt.q_occ_frac = atof(o.arg); // --q-occ-frac
else if (c == 352) mm_dbg_flag |= MM_DBG_PRINT_CHAIN; // --print-chains
else if (c == 353) opt.flag |= MM_F_NO_HASH_NAME; // --no-hash-name
else if (c == 330) { else if (c == 330) {
fprintf(stderr, "[WARNING] \033[1;31m --lj-min-ratio has been deprecated.\033[0m\n"); fprintf(stderr, "[WARNING] \033[1;31m --lj-min-ratio has been deprecated.\033[0m\n");
} else if (c == 314) { // --frag } else if (c == 314) { // --frag
@@ -410,7 +418,10 @@ int main(int argc, char *argv[])
if (mm_verbose >= 3) mm_idx_stat(mi); if (mm_verbose >= 3) mm_idx_stat(mi);
if (junc_bed) mm_idx_bed_read(mi, junc_bed, 1); if (junc_bed) mm_idx_bed_read(mi, junc_bed, 1);
if (alt_list) mm_idx_alt_read(mi, alt_list); if (alt_list) mm_idx_alt_read(mi, alt_list);
if (argc - (o.ind + 1) == 0) continue; // no query files if (argc - (o.ind + 1) == 0) {
mm_idx_destroy(mi);
continue; // no query files
}
ret = 0; ret = 0;
if (!(opt.flag & MM_F_FRAG_MODE)) { if (!(opt.flag & MM_F_FRAG_MODE)) {
for (i = o.ind + 1; i < argc; ++i) { for (i = o.ind + 1; i < argc; ++i) {
+16 -10
View File
@@ -212,7 +212,7 @@ static void chain_post(const mm_mapopt_t *opt, int max_chain_gap_ref, const mm_i
{ {
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s) if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop); mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
if (n_segs <= 1) mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs); if (n_segs <= 1) mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, 1, opt->max_gap * 0.8, n_regs, regs);
else mm_select_sub_multi(km, opt->pri_ratio, 0.2f, 0.7f, max_chain_gap_ref, mi->k*2, opt->best_n, n_segs, qlens, n_regs, regs); else mm_select_sub_multi(km, opt->pri_ratio, 0.2f, 0.7f, max_chain_gap_ref, mi->k*2, opt->best_n, n_segs, qlens, n_regs, regs);
} }
} }
@@ -223,7 +223,7 @@ static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *k
regs = mm_align_skeleton(km, opt, mi, qlen, seq, n_regs, regs, a); // this calls mm_filter_regs() regs = mm_align_skeleton(km, opt, mi, qlen, seq, n_regs, regs, a); // this calls mm_filter_regs()
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s) if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop); mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs); mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, 0, opt->max_gap * 0.8, n_regs, regs);
mm_set_sam_pri(*n_regs, regs); mm_set_sam_pri(*n_regs, regs);
} }
return regs; return regs;
@@ -240,6 +240,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
mm128_v mv = {0,0,0}; mm128_v mv = {0,0,0};
mm_reg1_t *regs0; mm_reg1_t *regs0;
km_stat_t kmst; km_stat_t kmst;
float chn_pen_gap, chn_pen_skip;
for (i = 0, qlen_sum = 0; i < n_segs; ++i) for (i = 0, qlen_sum = 0; i < n_segs; ++i)
qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0; qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0;
@@ -247,11 +248,12 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
if (qlen_sum == 0 || n_segs <= 0 || n_segs > MM_MAX_SEG) return; if (qlen_sum == 0 || n_segs <= 0 || n_segs > MM_MAX_SEG) return;
if (opt->max_qlen > 0 && qlen_sum > opt->max_qlen) return; if (opt->max_qlen > 0 && qlen_sum > opt->max_qlen) return;
hash = qname? __ac_X31_hash_string(qname) : 0; hash = qname && !(opt->flag & MM_F_NO_HASH_NAME)? __ac_X31_hash_string(qname) : 0;
hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed); hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed);
hash = __ac_Wang_hash(hash); hash = __ac_Wang_hash(hash);
collect_minimizers(b->km, opt, mi, n_segs, qlens, seqs, &mv); collect_minimizers(b->km, opt, mi, n_segs, qlens, seqs, &mv);
if (opt->q_occ_frac > 0.0f) mm_seed_mz_flt(b->km, &mv, opt->mid_occ, opt->q_occ_frac);
if (opt->flag & MM_F_HEAP_SORT) a = collect_seed_hits_heap(b->km, opt, opt->mid_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos); if (opt->flag & MM_F_HEAP_SORT) a = collect_seed_hits_heap(b->km, opt, opt->mid_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
else a = collect_seed_hits(b->km, opt, opt->mid_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos); else a = collect_seed_hits(b->km, opt, opt->mid_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
@@ -273,12 +275,14 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
if (max_chain_gap_ref < opt->max_gap) max_chain_gap_ref = opt->max_gap; if (max_chain_gap_ref < opt->max_gap) max_chain_gap_ref = opt->max_gap;
} else max_chain_gap_ref = opt->max_gap; } else max_chain_gap_ref = opt->max_gap;
chn_pen_gap = opt->chain_gap_scale * 0.01 * mi->k;
chn_pen_skip = opt->chain_skip_scale * 0.01 * mi->k;
if (opt->flag & MM_F_RMQ) { if (opt->flag & MM_F_RMQ) {
a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score, a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score,
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, n_a, a, &n_regs0, &u, b->km); chn_pen_gap, chn_pen_skip, n_a, a, &n_regs0, &u, b->km);
} else { } else {
a = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score, a = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score,
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km); chn_pen_gap, chn_pen_skip, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
} }
if (opt->bw_long > opt->bw && (opt->flag & (MM_F_SPLICE|MM_F_SR|MM_F_NO_LJOIN)) == 0 && n_segs == 1 && n_regs0 > 1) { // re-chain/long-join for long sequences if (opt->bw_long > opt->bw && (opt->flag & (MM_F_SPLICE|MM_F_SR|MM_F_NO_LJOIN)) == 0 && n_segs == 1 && n_regs0 > 1) { // re-chain/long-join for long sequences
@@ -289,7 +293,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
kfree(b->km, u); kfree(b->km, u);
radix_sort_128x(a, a + n_a); radix_sort_128x(a, a + n_a);
a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw_long, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score, a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw_long, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score,
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, n_a, a, &n_regs0, &u, b->km); chn_pen_gap, chn_pen_skip, n_a, a, &n_regs0, &u, b->km);
} }
} else if (opt->max_occ > opt->mid_occ && rep_len > 0 && !(opt->flag & MM_F_RMQ)) { // re-chain, mostly for short reads } else if (opt->max_occ > opt->mid_occ && rep_len > 0 && !(opt->flag & MM_F_RMQ)) { // re-chain, mostly for short reads
int rechain = 0; int rechain = 0;
@@ -312,7 +316,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
if (opt->flag & MM_F_HEAP_SORT) a = collect_seed_hits_heap(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos); if (opt->flag & MM_F_HEAP_SORT) a = collect_seed_hits_heap(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
else a = collect_seed_hits(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos); else a = collect_seed_hits(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
a = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score, a = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score,
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km); chn_pen_gap, chn_pen_skip, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
} }
} }
b->frag_gap = max_chain_gap_ref; b->frag_gap = max_chain_gap_ref;
@@ -324,15 +328,17 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
mm_hit_sort(b->km, &n_regs0, regs0, opt->alt_drop); // this step can be merged into mm_gen_regs(); will do if this shows up in profile mm_hit_sort(b->km, &n_regs0, regs0, opt->alt_drop); // this step can be merged into mm_gen_regs(); will do if this shows up in profile
} }
if (mm_dbg_flag & MM_DBG_PRINT_SEED) if (mm_dbg_flag & (MM_DBG_PRINT_SEED|MM_DBG_PRINT_CHAIN))
for (j = 0; j < n_regs0; ++j) for (j = 0; j < n_regs0; ++j)
for (i = regs0[j].as; i < regs0[j].as + regs0[j].cnt; ++i) for (i = regs0[j].as; i < regs0[j].as + regs0[j].cnt; ++i)
fprintf(stderr, "CN\t%d\t%s\t%d\t%c\t%d\t%d\t%d\n", j, mi->seq[a[i].x<<1>>33].name, (int32_t)a[i].x, "+-"[a[i].x>>63], (int32_t)a[i].y, (int32_t)(a[i].y>>32&0xff), fprintf(stderr, "CN\t%d\t%s\t%d\t%c\t%d\t%d\t%d\n", j, mi->seq[a[i].x<<1>>33].name, (int32_t)a[i].x, "+-"[a[i].x>>63], (int32_t)a[i].y, (int32_t)(a[i].y>>32&0xff),
i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x)); i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x));
chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a); chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a);
if (!is_sr && !(opt->flag&MM_F_QSTRAND)) if (!is_sr && !(opt->flag&MM_F_QSTRAND)) {
mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos); mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos);
n_regs0 = mm_filter_strand_retained(n_regs0, regs0);
}
if (n_segs == 1) { // uni-segment if (n_segs == 1) { // uni-segment
regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], &n_regs0, regs0, a); regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], &n_regs0, regs0, a);
@@ -505,7 +511,7 @@ static void merge_hits(step_t *s)
mm_hit_sort(km, &s->n_reg[k], s->reg[k], opt->alt_drop); mm_hit_sort(km, &s->n_reg[k], s->reg[k], opt->alt_drop);
mm_set_parent(km, opt->mask_level, opt->mask_len, s->n_reg[k], s->reg[k], opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop); mm_set_parent(km, opt->mask_level, opt->mask_len, s->n_reg[k], s->reg[k], opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
if (!(opt->flag & MM_F_ALL_CHAINS)) { if (!(opt->flag & MM_F_ALL_CHAINS)) {
mm_select_sub(km, opt->pri_ratio, s->p->mi->k*2, opt->best_n, &s->n_reg[k], s->reg[k]); mm_select_sub(km, opt->pri_ratio, s->p->mi->k*2, opt->best_n, 0, opt->max_gap * 0.8, &s->n_reg[k], s->reg[k]);
mm_set_sam_pri(s->n_reg[k], s->reg[k]); mm_set_sam_pri(s->n_reg[k], s->reg[k]);
} }
mm_set_mapq(km, s->n_reg[k], s->reg[k], opt->min_chain_score, opt->a, rep_len, !!(opt->flag & MM_F_SR)); mm_set_mapq(km, s->n_reg[k], s->reg[k], opt->min_chain_score, opt->a, rep_len, !!(opt->flag & MM_F_SR));
+4 -1
View File
@@ -39,6 +39,7 @@
#define MM_F_RMQ (0x80000000LL) #define MM_F_RMQ (0x80000000LL)
#define MM_F_QSTRAND (0x100000000LL) #define MM_F_QSTRAND (0x100000000LL)
#define MM_F_NO_INV (0x200000000LL) #define MM_F_NO_INV (0x200000000LL)
#define MM_F_NO_HASH_NAME (0x400000000LL)
#define MM_I_HPC 0x1 #define MM_I_HPC 0x1
#define MM_I_NO_SEQ 0x2 #define MM_I_NO_SEQ 0x2
@@ -108,7 +109,7 @@ typedef struct {
int32_t mlen, blen; // seeded exact match length; seeded alignment block length int32_t mlen, blen; // seeded exact match length; seeded alignment block length
int32_t n_sub; // number of suboptimal mappings int32_t n_sub; // number of suboptimal mappings
int32_t score0; // initial chaining score (before chain merging/spliting) int32_t score0; // initial chaining score (before chain merging/spliting)
uint32_t mapq:8, split:2, rev:1, inv:1, sam_pri:1, proper_frag:1, pe_thru:1, seg_split:1, seg_id:8, split_inv:1, is_alt:1, dummy:6; uint32_t mapq:8, split:2, rev:1, inv:1, sam_pri:1, proper_frag:1, pe_thru:1, seg_split:1, seg_id:8, split_inv:1, is_alt:1, strand_retained:1, dummy:5;
uint32_t hash; uint32_t hash;
float div; float div;
mm_extra_t *p; mm_extra_t *p;
@@ -135,6 +136,7 @@ typedef struct {
int min_cnt; // min number of minimizers on each chain int min_cnt; // min number of minimizers on each chain
int min_chain_score; // min chaining score int min_chain_score; // min chaining score
float chain_gap_scale; float chain_gap_scale;
float chain_skip_scale;
int rmq_size_cap, rmq_inner_dist; int rmq_size_cap, rmq_inner_dist;
int rmq_rescue_size; int rmq_rescue_size;
float rmq_rescue_ratio; float rmq_rescue_ratio;
@@ -163,6 +165,7 @@ typedef struct {
int pe_ori, pe_bonus; int pe_ori, pe_bonus;
float mid_occ_frac; // only used by mm_mapopt_update(); see below float mid_occ_frac; // only used by mm_mapopt_update(); see below
float q_occ_frac;
int32_t min_mid_occ, max_mid_occ; int32_t min_mid_occ, max_mid_occ;
int32_t mid_occ; // ignore seeds with occurrences above this threshold int32_t mid_occ; // ignore seeds with occurrences above this threshold
int32_t max_occ, max_max_occ, occ_dist; int32_t max_occ, max_max_occ, occ_dist;
+21 -7
View File
@@ -1,4 +1,4 @@
.TH minimap2 1 "6 July 2021" "minimap2-2.21 (r1071)" "Bioinformatics tools" .TH minimap2 1 "18 December 2021" "minimap2-2.24 (r1122)" "Bioinformatics tools"
.SH NAME .SH NAME
.PP .PP
minimap2 - mapping and alignment between collections of DNA sequences minimap2 - mapping and alignment between collections of DNA sequences
@@ -77,7 +77,7 @@ SAM format.
Minimizer k-mer length [15] Minimizer k-mer length [15]
.TP .TP
.BI -w \ INT .BI -w \ INT
Minimizer window size [2/3 of k-mer length]. A minimizer is the smallest k-mer Minimizer window size [10]. A minimizer is the smallest k-mer
in a window of w consecutive k-mers. in a window of w consecutive k-mers.
.TP .TP
.B -H .B -H
@@ -151,10 +151,16 @@ Lower and upper bounds of k-mer occurrences [10,1000000]. The final k-mer occurr
.BR -f }}. .BR -f }}.
This option prevents excessively small or large This option prevents excessively small or large
.B -f .B -f
estimated from the input reference. It deprecates estimated from the input reference. Available since r1034 and deprecating
.B --min-occ-floor .B --min-occ-floor
in earlier versions of minimap2. in earlier versions of minimap2.
.TP .TP
.BI --q-occ-frac \ FLOAT
Discard a query minimizer if its occurrence is higher than
.I FLOAT
fraction of query minimizers and than the reference occurrence threshold
[0.01]. Set 0 to disable. Available since r1105.
.TP
.BI -e \ INT .BI -e \ INT
Sample a high-frequency minimizer every Sample a high-frequency minimizer every
.I INT .I INT
@@ -312,6 +318,9 @@ faster for short reads, but slower for long reads. [no]
.B --no-pairing .B --no-pairing
Treat two reads in a pair as independent reads. The mate related fields in SAM Treat two reads in a pair as independent reads. The mate related fields in SAM
are still properly populated. are still properly populated.
.TP
.B --no-hash-name
Produce the same alignment for identical sequences regardless of their sequence names.
.SS Alignment options .SS Alignment options
.TP 10 .TP 10
.BI -A \ INT .BI -A \ INT
@@ -423,6 +432,11 @@ alignment.
Skip alignment if the DP matrix size is above Skip alignment if the DP matrix size is above
.IR NUM . .IR NUM .
Set 0 to disable [100m]. Set 0 to disable [100m].
.TP
.BI --cap-kalloc \ NUM
Free thread-local kalloc memory reservoir if after the alignment the size of the reservoir above
.IR NUM .
Set 0 to disable [0].
.SS Input/output options .SS Input/output options
.TP 10 .TP 10
.B -a .B -a
@@ -551,7 +565,7 @@ Align older PacBio continuous long (CLR) reads to a reference genome
.B asm5 .B asm5
Long assembly to reference mapping Long assembly to reference mapping
.RB ( -k19 .RB ( -k19
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B19 -O39,81 -E3,1 -s200 -z200 .B -w19 -U50,500 --rmq -r1k,100k -g10k -A1 -B19 -O39,81 -E3,1 -s200 -z200
.BR -N50 ). .BR -N50 ).
Typically, the alignment will not extend to regions with 5% or higher sequence Typically, the alignment will not extend to regions with 5% or higher sequence
divergence. Only use this preset if the average divergence is far below 5%. divergence. Only use this preset if the average divergence is far below 5%.
@@ -559,14 +573,14 @@ divergence. Only use this preset if the average divergence is far below 5%.
.B asm10 .B asm10
Long assembly to reference mapping Long assembly to reference mapping
.RB ( -k19 .RB ( -k19
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B9 -O16,41 -E2,1 -s200 -z200 .B -w19 -U50,500 --rmq -r1k,100k -g10k -A1 -B9 -O16,41 -E2,1 -s200 -z200
.BR -N50 ). .BR -N50 ).
Up to 10% sequence divergence. Up to 10% sequence divergence.
.TP .TP
.B asm20 .B asm20
Long assembly to reference mapping Long assembly to reference mapping
.RB ( -k19 .RB ( -k19
.B -w10 -U50,500 --rmq -r100k -g10k -A1 -B4 -O6,26 -E2,1 -s200 -z200 .B -w10 -U50,500 --rmq -r1k,100k -g10k -A1 -B4 -O6,26 -E2,1 -s200 -z200
.BR -N50 ). .BR -N50 ).
Up to 20% sequence divergence. Up to 20% sequence divergence.
.TP .TP
@@ -592,7 +606,7 @@ Long-read splice alignment for PacBio CCS reads
.B sr .B sr
Short single-end reads without splicing Short single-end reads without splicing
.RB ( -k21 .RB ( -k21
.B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -b0 -r100 -p.5 -N20 -f1000,5000 -n2 -m20 .B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -b0 -r100 -p.5 -N20 -f1000,5000 -n2 -m25
.B -s40 -g100 -2K50m --heap-sort=yes .B -s40 -g100 -2K50m --heap-sort=yes
.BR --secondary=no ). .BR --secondary=no ).
.TP .TP
+27 -4
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env k8 #!/usr/bin/env k8
var paftools_version = '2.21-r1071'; var paftools_version = '2.24-r1122';
/***************************** /*****************************
***** Library functions ***** ***** Library functions *****
@@ -1532,12 +1532,13 @@ function paf_view(args)
function paf_gff2bed(args) function paf_gff2bed(args)
{ {
var c, fn_ucsc_fai = null, is_short = false, keep_gff = false, print_junc = false; var c, fn_ucsc_fai = null, is_short = false, keep_gff = false, print_junc = false, output_gene = false;
while ((c = getopt(args, "u:sgj")) != null) { while ((c = getopt(args, "u:sgjG")) != null) {
if (c == 'u') fn_ucsc_fai = getopt.arg; if (c == 'u') fn_ucsc_fai = getopt.arg;
else if (c == 's') is_short = true; else if (c == 's') is_short = true;
else if (c == 'g') keep_gff = true; else if (c == 'g') keep_gff = true;
else if (c == 'j') print_junc = true; else if (c == 'j') print_junc = true;
else if (c == 'G') output_gene = true;
} }
if (getopt.ind == args.length) { if (getopt.ind == args.length) {
@@ -1607,6 +1608,8 @@ function paf_gff2bed(args)
var re_gtf = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name) "([^"]+)";/g; var re_gtf = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name) "([^"]+)";/g;
var re_gff3 = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name)=([^;]+)/g; var re_gff3 = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name)=([^;]+)/g;
var re_gtf_gene = /\b(gene_id|gene_type|gene_name) "([^;]+)";/g;
var re_gff3_gene = /\b(gene_id|gene_type|source_gene|gene_biotype|gene_name)=([^;]+);/g;
var buf = new Bytes(); var buf = new Bytes();
var file = args[getopt.ind] == '-'? new File() : new File(args[getopt.ind]); var file = args[getopt.ind] == '-'? new File() : new File(args[getopt.ind]);
@@ -1620,6 +1623,26 @@ function paf_gff2bed(args)
continue; continue;
} }
if (t[0].charAt(0) == '#') continue; if (t[0].charAt(0) == '#') continue;
if (output_gene) {
var id = null, src = null, biotype = null, type = "", name = "N/A";
if (t[2] != "gene") continue;
while ((m = re_gtf_gene.exec(t[8])) != null) {
if (m[1] == "gene_id") id = m[2];
else if (m[1] == "gene_type") type = m[2];
else if (m[1] == "gene_name") name = m[2];
}
while ((m = re_gff3_gene.exec(t[8])) != null) {
if (m[1] == "gene_id") id = m[2];
else if (m[1] == "source_gene") src = m[2];
else if (m[1] == "gene_type") type = m[2];
else if (m[1] == "gene_biotype") biotype = m[2];
else if (m[1] == "gene_name") name = m[2];
}
if (src != null) id = src;
if (type == "" && biotype != null) type = biotype;
print(t[0], parseInt(t[3]) - 1, t[4], [id, type, name].join("|"), 1000, t[6]);
continue;
}
if (t[2] != "CDS" && t[2] != "exon") continue; if (t[2] != "CDS" && t[2] != "exon") continue;
t[3] = parseInt(t[3]) - 1; t[3] = parseInt(t[3]) - 1;
t[4] = parseInt(t[4]); t[4] = parseInt(t[4]);
@@ -2951,7 +2974,7 @@ function paf_pafcmp(args)
{ {
var c, opt = { min_len:5000, min_mapq:10, min_ovlp:0.5 }; var c, opt = { min_len:5000, min_mapq:10, min_ovlp:0.5 };
while ((c = getopt(args, "q:")) != null) { while ((c = getopt(args, "q:")) != null) {
if (c == 'q') opt.min_mapq = parseInt(opt.arg); if (c == 'q') opt.min_mapq = parseInt(getopt.arg);
} }
var buf = new Bytes(); var buf = new Bytes();
+4 -1
View File
@@ -13,6 +13,7 @@
#define MM_DBG_PRINT_QNAME 0x2 #define MM_DBG_PRINT_QNAME 0x2
#define MM_DBG_PRINT_SEED 0x4 #define MM_DBG_PRINT_SEED 0x4
#define MM_DBG_PRINT_ALN_SEQ 0x8 #define MM_DBG_PRINT_ALN_SEQ 0x8
#define MM_DBG_PRINT_CHAIN 0x10
#define MM_SEED_LONG_JOIN (1ULL<<40) #define MM_SEED_LONG_JOIN (1ULL<<40)
#define MM_SEED_IGNORE (1ULL<<41) #define MM_SEED_IGNORE (1ULL<<41)
@@ -61,6 +62,7 @@ uint32_t ks_ksmall_uint32_t(size_t n, uint32_t arr[], size_t kk);
void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, int is_hpc, mm128_v *p); void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, int is_hpc, mm128_v *p);
mm_seed_t *mm_collect_matches(void *km, int *_n_m, int qlen, int max_occ, int max_max_occ, int dist, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos); mm_seed_t *mm_collect_matches(void *km, int *_n_m, int qlen, int max_occ, int max_max_occ, int dist, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos);
void mm_seed_mz_flt(void *km, mm128_v *mv, int32_t q_occ_max, float q_occ_frac);
double mm_event_identity(const mm_reg1_t *r); double mm_event_identity(const mm_reg1_t *r);
int mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]); int mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]);
@@ -90,8 +92,9 @@ void mm_sync_regs(void *km, int n_regs, mm_reg1_t *regs);
int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a); int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a);
int mm_set_sam_pri(int n, mm_reg1_t *r); int mm_set_sam_pri(int n, mm_reg1_t *r);
void mm_set_parent(void *km, float mask_level, int mask_len, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level, float alt_diff_frac); void mm_set_parent(void *km, float mask_level, int mask_len, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level, float alt_diff_frac);
void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_, mm_reg1_t *r); void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int check_strand, int min_strand_sc, int *n_, mm_reg1_t *r);
void mm_select_sub_multi(void *km, float pri_ratio, float pri1, float pri2, int max_gap_ref, int min_diff, int best_n, int n_segs, const int *qlens, int *n_, mm_reg1_t *r); void mm_select_sub_multi(void *km, float pri_ratio, float pri1, float pri2, int max_gap_ref, int min_diff, int best_n, int n_segs, const int *qlens, int *n_, mm_reg1_t *r);
int mm_filter_strand_retained(int n_regs, mm_reg1_t *r);
void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs); void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs);
void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r, float alt_diff_frac); void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r, float alt_diff_frac);
void mm_set_mapq(void *km, int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr); void mm_set_mapq(void *km, int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr);
+5 -1
View File
@@ -19,6 +19,7 @@ void mm_mapopt_init(mm_mapopt_t *opt)
opt->min_mid_occ = 10; opt->min_mid_occ = 10;
opt->max_mid_occ = 1000000; opt->max_mid_occ = 1000000;
opt->sdust_thres = 0; // no SDUST masking opt->sdust_thres = 0; // no SDUST masking
opt->q_occ_frac = 0.01f;
opt->min_cnt = 3; opt->min_cnt = 3;
opt->min_chain_score = 40; opt->min_chain_score = 40;
@@ -32,6 +33,7 @@ void mm_mapopt_init(mm_mapopt_t *opt)
opt->rmq_rescue_size = 1000; opt->rmq_rescue_size = 1000;
opt->rmq_rescue_ratio = 0.1f; opt->rmq_rescue_ratio = 0.1f;
opt->chain_gap_scale = 0.8f; opt->chain_gap_scale = 0.8f;
opt->chain_skip_scale = 0.0f;
opt->max_max_occ = 4095; opt->max_max_occ = 4095;
opt->occ_dist = 500; opt->occ_dist = 500;
@@ -52,6 +54,7 @@ void mm_mapopt_init(mm_mapopt_t *opt)
opt->max_clip_ratio = 1.0f; opt->max_clip_ratio = 1.0f;
opt->mini_batch_size = 500000000; opt->mini_batch_size = 500000000;
opt->max_sw_mat = 100000000; opt->max_sw_mat = 100000000;
opt->cap_kalloc = 1000000000;
opt->rank_min_len = 500; opt->rank_min_len = 500;
opt->rank_frac = 0.9f; opt->rank_frac = 0.9f;
@@ -71,6 +74,7 @@ void mm_mapopt_update(mm_mapopt_t *opt, const mm_idx_t *mi)
if (opt->max_mid_occ > opt->min_mid_occ && opt->mid_occ > opt->max_mid_occ) if (opt->max_mid_occ > opt->min_mid_occ && opt->mid_occ > opt->max_mid_occ)
opt->mid_occ = opt->max_mid_occ; opt->mid_occ = opt->max_mid_occ;
} }
if (opt->bw_long < opt->bw) opt->bw_long = opt->bw;
if (mm_verbose >= 3) if (mm_verbose >= 3)
fprintf(stderr, "[M::%s::%.3f*%.2f] mid_occ = %d\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), opt->mid_occ); fprintf(stderr, "[M::%s::%.3f*%.2f] mid_occ = %d\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), opt->mid_occ);
} }
@@ -110,7 +114,7 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
mo->min_dp_max = 200; mo->min_dp_max = 200;
} else if (strncmp(preset, "asm", 3) == 0) { } else if (strncmp(preset, "asm", 3) == 0) {
io->flag = 0, io->k = 19, io->w = 19; io->flag = 0, io->k = 19, io->w = 19;
mo->bw = mo->bw_long = 100000; mo->bw = 1000, mo->bw_long = 100000;
mo->max_gap = 10000; mo->max_gap = 10000;
mo->flag |= MM_F_RMQ; mo->flag |= MM_F_RMQ;
mo->min_mid_occ = 50, mo->max_mid_occ = 500; mo->min_mid_occ = 50, mo->max_mid_occ = 500;
+6
View File
@@ -23,6 +23,7 @@ cdef extern from "minimap.h":
int min_cnt int min_cnt
int min_chain_score int min_chain_score
float chain_gap_scale float chain_gap_scale
float chain_skip_scale
int rmq_size_cap, rmq_inner_dist int rmq_size_cap, rmq_inner_dist
int rmq_rescue_size int rmq_rescue_size
float rmq_rescue_ratio float rmq_rescue_ratio
@@ -45,14 +46,19 @@ cdef extern from "minimap.h":
int anchor_ext_len, anchor_ext_shift int anchor_ext_len, anchor_ext_shift
float max_clip_ratio float max_clip_ratio
int rank_min_len
float rank_frac
int pe_ori, pe_bonus int pe_ori, pe_bonus
float mid_occ_frac float mid_occ_frac
float q_occ_frac
int32_t min_mid_occ int32_t min_mid_occ
int32_t mid_occ int32_t mid_occ
int32_t max_occ int32_t max_occ
int64_t mini_batch_size int64_t mini_batch_size
int64_t max_sw_mat int64_t max_sw_mat
int64_t cap_kalloc
const char *split_prefix const char *split_prefix
+1 -1
View File
@@ -3,7 +3,7 @@ from libc.stdlib cimport free
cimport cmappy cimport cmappy
import sys import sys
__version__ = '2.21' __version__ = '2.24'
cmappy.mm_reset_timer() cmappy.mm_reset_timer()
+25
View File
@@ -2,6 +2,31 @@
#include "kalloc.h" #include "kalloc.h"
#include "ksort.h" #include "ksort.h"
void mm_seed_mz_flt(void *km, mm128_v *mv, int32_t q_occ_max, float q_occ_frac)
{
mm128_t *a;
size_t i, j, st;
if (mv->n <= q_occ_max || q_occ_frac <= 0.0f || q_occ_max <= 0) return;
KMALLOC(km, a, mv->n);
for (i = 0; i < mv->n; ++i)
a[i].x = mv->a[i].x, a[i].y = i;
radix_sort_128x(a, a + mv->n);
for (st = 0, i = 1; i <= mv->n; ++i) {
if (i == mv->n || a[i].x != a[st].x) {
int32_t cnt = i - st;
if (cnt > q_occ_max && cnt > mv->n * q_occ_frac)
for (j = st; j < i; ++j)
mv->a[a[j].y].x = 0;
st = i;
}
}
kfree(km, a);
for (i = j = 0; i < mv->n; ++i)
if (mv->a[i].x != 0)
mv->a[j++] = mv->a[i];
mv->n = j;
}
mm_seed_t *mm_seed_collect_all(void *km, const mm_idx_t *mi, const mm128_v *mv, int32_t *n_m_) mm_seed_t *mm_seed_collect_all(void *km, const mm_idx_t *mi, const mm128_v *mv, int32_t *n_m_)
{ {
mm_seed_t *m; mm_seed_t *m;
+1 -1
View File
@@ -23,7 +23,7 @@ def readme():
setup( setup(
name = 'mappy', name = 'mappy',
version = '2.21', version = '2.24',
url = 'https://github.com/lh3/minimap2', url = 'https://github.com/lh3/minimap2',
description = 'Minimap2 python binding', description = 'Minimap2 python binding',
long_description = readme(), long_description = readme(),
+10 -1
View File
@@ -370,7 +370,6 @@
year = {2020}, year = {2020},
doi = {10.1101/2020.11.01.363887}, doi = {10.1101/2020.11.01.363887},
publisher = {Cold Spring Harbor Laboratory}, publisher = {Cold Spring Harbor Laboratory},
abstract = {About 5-10\% of the human genome remains inaccessible for functional analysis due to the presence of repetitive sequences such as segmental duplications and tandem repeat arrays. To enable high-quality resequencing of personal genomes, it is crucial to support end-to-end genome variant discovery using repeat-aware read mapping methods. In this study, we highlight the fact that existing long read mappers often yield incorrect alignments and variant calls within long, near-identical repeats, as they remain vulnerable to allelic bias. In the presence of a non-reference allele within a repeat, a read sampled from that region could be mapped to an incorrect repeat copy because the standard pairwise sequence alignment scoring system penalizes true variants.To address the above problem, we propose a novel, long read mapping method that addresses allelic bias by making use of minimal confidently alignable substrings (MCASs). MCASs are formulated as minimal length substrings of a read that have unique alignments to a reference locus with sufficient mapping confidence (i.e., a mapping quality score above a user-specified threshold). This approach treats each read mapping as a collection of confident sub-alignments, which is more tolerant of structural variation and more sensitive to paralog-specific variants (PSVs) within repeats. We mathematically define MCASs and discuss an exact algorithm as well as a practical heuristic to compute them. The proposed method, referred to as Winnowmap2, is evaluated using simulated as well as real long read benchmarks using the recently completed gapless assemblies of human chromosomes X and 8 as a reference. We show that Winnowmap2 successfully addresses the issue of allelic bias, enabling more accurate downstream variant calls in repetitive sequences. As an example, using simulated PacBio HiFi reads and structural variants in chromosome 8, Winnowmap2 alignments achieved the lowest false-negative and false-positive rates (1.89\%, 1.89\%) for calling structural variants within near-identical repeats compared to minimap2 (39.62\%, 5.88\%) and NGMLR (56.60\%, 36.11\%) respectively.Winnowmap2 code is accessible at https://github.com/marbl/WinnowmapCompeting Interest StatementThe authors have declared no competing interest.},
URL = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887}, URL = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887},
eprint = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887.full.pdf}, eprint = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887.full.pdf},
journal = {bioRxiv} journal = {bioRxiv}
@@ -449,3 +448,13 @@
Title = {A synthetic-diploid benchmark for accurate variant-calling evaluation}, Title = {A synthetic-diploid benchmark for accurate variant-calling evaluation},
Volume = {15}, Volume = {15},
Year = {2018}} Year = {2018}}
@article{Gu:1995wt,
author = {Gu, X and Li, W H},
journal = {J Mol Evol},
month = {Apr},
number = {4},
pages = {464-73},
title = {The size distribution of insertions and deletions in human and rodent pseudogenes suggests the logarithmic gap penalty for sequence alignment},
volume = {40},
year = {1995}}
+55 -40
View File
@@ -57,8 +57,8 @@ in v2.19 through v2.22 to improve mapping results.
\begin{methods} \begin{methods}
\section{Methods} \section{Methods}
\subsection{Rescuing high-occurrence $k$-mers} \subsection{Rescuing high-occurrence $k$-mers}\label{sec:high-occ}
Minimap2 keeps all $k$-mer minimizers during indexing. Its original Minimap2 keeps all $k$-mer minimizers~\citep{Roberts:2004fv} during indexing. Its original
implementation only selected low-occurrence minimizers during mapping. The implementation only selected low-occurrence minimizers during mapping. The
cutoff is a few hundred for mapping long reads against a human genome. If a cutoff is a few hundred for mapping long reads against a human genome. If a
read habors only a few or even no low-occurrence minimizers, it will fail read habors only a few or even no low-occurrence minimizers, it will fail
@@ -66,23 +66,24 @@ chaining due to insufficient anchors.
To resolve this issue, we implemented a new heuristic to add additional To resolve this issue, we implemented a new heuristic to add additional
minimizers. Suppose we are looking at two adjacent low-occurence $k$-mers minimizers. Suppose we are looking at two adjacent low-occurence $k$-mers
located at position $x_1$ and $x_2$, respectively. If $|x_1-x_2|\ge500$, located at position $x_1$ and $x_2$, respectively. If $|x_1-x_2|\ge L$,
minimap2 v2.22 additionally selects $\lfloor|x_1-x_2|/500\rfloor$ minimizers minimap2 v2.22 additionally selects $\lfloor|x_1-x_2|/L\rfloor$ minimizers
of the lowest occurrence among minimizers between $x_1$ and $x_2$. of the lowest occurrence among minimizers between $x_1$ and $x_2$. Here
We use a binary heap data parameter $L$ controls the frequency of sampling. It defaults to 500.
structure to select minimizers of the lowest occurrence in this interval.
This strategy adds necessary anchors at the cost of increasing total alignment This strategy adds necessary anchors at the cost of increasing total alignment
time by a few percent on real data. time by a few percent on real data.
\subsection{Aligning through longer INDELs} \subsection{Aligning through longer INDELs}
The original minimap2 may fail to align long INDELs due to its chaining The original minimap2 may fail to align long INDELs due to its chaining
heuristics. Briefly, minimap2 applies dynamic programming (DP) to chain heuristics. Briefly, minimap2 applies dynamic programming (DP) to chain
minimizer anchors. This is a quadratic algorithm, which is slow for chaining minimizer anchors. This is a quadratic algorithm, slow for chaining
contigs. For acceptable performance, the original minimap2 uses a 500bp band by contigs. For acceptable performance, the original minimap2 uses a 500bp band by
default. If there is an INDEL longer than 500bp and the two chains around the INDEL default, which means a gap longer than 500bp will stop chaining.
To align through longer gaps, older minimap2 implemented a long-join heurstic as follows.
If there is an INDEL longer than 500bp and the two chains around the INDEL
have no overlaps on either the query or the reference sequence, minimap2 may have no overlaps on either the query or the reference sequence, minimap2 may
join the two short chains later at a later step. We call it the join the two short chains later.
long-join heuristic. This heuristic may fail around VNTRs because short chains This heuristic may fail around VNTRs because short chains
often have overlaps in VNTRs. More subtly, minimap2 may escape the inner DP often have overlaps in VNTRs. More subtly, minimap2 may escape the inner DP
loop early, again for performance, if the chaining result is not improved for loop early, again for performance, if the chaining result is not improved for
50 iterations. When there is a copy number change in a long segmental 50 iterations. When there is a copy number change in a long segmental
@@ -90,13 +91,13 @@ duplication, the early escape may break around the event even if users
specify a large band. specify a large band.
In minigraph~\citep{Li:2020aa}, we developed a new chaining algorithm that In minigraph~\citep{Li:2020aa}, we developed a new chaining algorithm that
finds short INDELs with DP-based chaining and goes through long INDELs with a finds up to 1kb INDELs with DP-based chaining and goes through longer INDELs with a
subquadratic algorithm~\citep{DBLP:conf/wabi/AbouelhodaO03}. We ported the same subquadratic algorithm~\citep{DBLP:conf/wabi/AbouelhodaO03}. We ported the same
algorithm to minimap2 for contig mapping. For long-read mapping, the minigraph algorithm to minimap2 for contig mapping. For long-read mapping, the minigraph
algorithm is slower. Minimap2 v2.22 now still uses the DP-based algorithm to algorithm is slower. Minimap2 v2.22 still uses the DP-based algorithm to
find short chains and then invokes the minigraph algorithm to rechain anchors in find short chains and then invokes the minigraph algorithm to rechain anchors in
these short chains. The rechaining step achieves the same goal as long-join these short chains. The rechaining step achieves the same goal as long-join
but is more reliable as it can resolve overlaps between short chains. The old but is more reliable because it can resolve overlaps between short chains. The old
long-join heuristic has since been removed. long-join heuristic has since been removed.
\subsection{Properly mapping long reads with SVs} \subsection{Properly mapping long reads with SVs}
@@ -106,25 +107,25 @@ the best scoring alignment is sometimes not the correct alignment.
\citet{Jain2020.11.01.363887} resolved this dilemma by altering the mapping \citet{Jain2020.11.01.363887} resolved this dilemma by altering the mapping
algorithm. algorithm.
In our view, this problem is rooted in impropriate scoring: affine-gap penalty In our view, this problem is rooted in inapropriate scoring: affine-gap penalty
over-penalizes a long INDEL that was often evolutionarily created in one event. over-penalizes a long INDEL that was often evolutionarily created in one event.
We should not penalize a SV linearly in its length. Minimap2 v2.22 rescores We should not penalize a SV by a function linear in the SV length. Minimap2 v2.22 instead rescores
an alignment with the following scoring function. Suppose an alignment consists an alignment with the following scoring function. Suppose an alignment consists
of $M$ matching bases, $N$ substitutions and $G$ gap opens, we empirically of $M$ matching bases, $N$ substitutions and $G$ gap opens, we empirically
score the alignment with score the alignment with
$$ $$
M-\frac{N+G}{2d}-\sum_{i=1}^G\log_2(1+g_i) S=M-\frac{N+G}{2d}-\sum_{i=1}^G\log_2(1+g_i)
$$ $$
where $g_i\ge1$ is the length of the $i$-th gap and where $g_i\ge1$ is the length of the $i$-th gap and
$$ $$
d=\max\left\{\frac{N+G}{M+N+G},0.02\right\} d=\max\left\{\frac{N+G}{M+N+G},0.02\right\}
$$ $$
Here $d$ approximates per-base sequence divergence with the smallest value set It approximates per-base sequence divergence except with the smallest value set
to 2\%. As an analogy to affine-gap scoring, the matching score in our scheme to 2\%. As an analogy to affine-gap scoring, the matching score in our scheme
is 1, the mismatch and gap open penalties are both $1/2d$ and the gap extension is 1, the mismatch and gap open penalties are both $1/2d$ and the gap extension
penalty is a logarithm function of the gap length. Our scoring gives a long SV penalty is a logarithm function of the gap length~\citep{Gu:1995wt}. Our scoring gives a long SV
a much milder penalty. In terms of time complexity, scoring an alignment is a much milder penalty. In terms of time complexity, scoring an alignment is
linear in the length of the alignment. Time spent on rescoring is negligible in linear in the length of the alignment. The time spent on rescoring is negligible in
practice. practice.
%If we assume sequences evolve under a duplication-mutation model, we may have a %If we assume sequences evolve under a duplication-mutation model, we may have a
@@ -144,9 +145,11 @@ practice.
\toprule \toprule
$[$Benchmark$]$ Metric & v2.22 & v2.18 & Winno & lra \\ $[$Benchmark$]$ Metric & v2.22 & v2.18 & Winno & lra \\
\midrule \midrule
$[$sim-map$]$ \% mapped reads at Q10 & 97.9 & 97.6 & {\bf 99.0} & 97.3 \\ $[$sim-map$]$ \% mapped reads at Q10 & 97.9 & 97.6 & {\bf 99.0}& 97.3 \\
$[$sim-map$]$ err. rate at Q10 (phredQ) & {\bf 52} & {\bf 52} & 38 & 24 \\ $[$sim-map$]$ err. rate at Q10 (phredQ) & {\bf 52} & {\bf 52} & 38 & 24 \\
$[$winno-cmp$]$ rate of diff. (phredQ) & {\bf 41} & 37 & N/A & 18 \\ $[$winno-cmp$]$ rate of diff. (phredQ) & {\bf 41} & 37 & truth & 18 \\
$[$winno-cmp$]$ CPU time (hour) & {\bf 5.0} & 5.3 & 71.8 & 13.1 \\
$[$winno-cmp$]$ peak RAM (Gb) & 17.1 & 14.4 & {\bf 9.6} & 12.4 \\
$[$sim-sv$]$ \% false negative rate & {\bf 0.5} & 2.0 & {\bf 0.5} & 1.4 \\ $[$sim-sv$]$ \% false negative rate & {\bf 0.5} & 2.0 & {\bf 0.5} & 1.4 \\
$[$sim-sv$]$ \% false discovery rate & {\bf 0.0} & 0.1 & {\bf 0.0} & 0.1 \\ $[$sim-sv$]$ \% false discovery rate & {\bf 0.0} & 0.1 & {\bf 0.0} & 0.1 \\
$[$real-sv-1k$]$ \% false negative rate & {\bf 7.3} & 20.0 & 13.0 & N/A \\ $[$real-sv-1k$]$ \% false negative rate & {\bf 7.3} & 20.0 & 13.0 & N/A \\
@@ -159,11 +162,11 @@ $[$real-sv-1k$]$ \% false discovery rate & 2.7 & {\bf 2.4} & 2.7 & N/A \\
10 or higher were evaluated by ``paftools.js mapeval''. The mapping error rate 10 or higher were evaluated by ``paftools.js mapeval''. The mapping error rate
is measured in the phred scale: if the error rate is $e$, $-10\log_{10}e$ is is measured in the phred scale: if the error rate is $e$, $-10\log_{10}e$ is
reported in the table. In $[$winno-cmp$]$, 1.39 million CHM13 HiFi reads from reported in the table. In $[$winno-cmp$]$, 1.39 million CHM13 HiFi reads from
SRR11292121 were mapped against CHM13. 99.3\% of them were mapped by Winnowmap2 SRR11292121 were mapped against the same CHM13 assembly. 99.3\% of them were mapped by Winnowmap2
at mapping quality 10 or higher and were taken as ground truth to evaluate at mapping quality 10 or higher and were taken as ground truth to evaluate
minimap2 and lra with ``paftools.js pafcmp''. $[$sim-sv$]$ simulated 1,000 minimap2 and lra with ``paftools.js pafcmp''. $[$sim-sv$]$ simulated 1,000
50bp to 1000bp INDELs from chr8 in CHM13 using SURVIVOR~\citep{Jeffares:2017aa} and simulated Nanopore 50bp to 1000bp INDELs from chr8 in CHM13 using SURVIVOR~\citep{Jeffares:2017aa} and simulated Nanopore
reads at 30 folds with the same pbsim2 command line. SVs were called with reads at 30-fold coverage with the same pbsim2 command line. SVs were called with
``sniffles -q 10''~\citep{Sedlazeck:2018ab} and compared to the simulated truth with ``SURVIVOR eval ``sniffles -q 10''~\citep{Sedlazeck:2018ab} and compared to the simulated truth with ``SURVIVOR eval
call.vcf truth.bed 50''. In $[$real-sv-1k$]$, small and long variants were call.vcf truth.bed 50''. In $[$real-sv-1k$]$, small and long variants were
called by dipcall-0.3~\citep{Li:2018aa} for HG002 assemblies (AC: GCA\_018852605.1 and called by dipcall-0.3~\citep{Li:2018aa} for HG002 assemblies (AC: GCA\_018852605.1 and
@@ -172,31 +175,44 @@ GCA\_018852615.1) and compared to the GIAB truth~\citep{Zook:2020aa} using ``tru
\end{table} \end{table}
We evaluated minimap2 v2.22 along with v2.18, Winnowmap2 v2.03 and lra v1.3.2 We evaluated minimap2 v2.22 along with v2.18, Winnowmap2 v2.03 and lra v1.3.2
(Table~\ref{tab:1}). Both versions of minimap2 achieved high mapping accuracy on (Table~\ref{tab:1}), using the default setting of each mapper according to the input data types.
Both versions of minimap2 achieved high mapping accuracy on
simulated Nanopore reads (sim-map). Winnowmap2 aligned more reads at mapping simulated Nanopore reads (sim-map). Winnowmap2 aligned more reads at mapping
quality 10 or higher (mapQ10). However, it may occasionally assign a high mapping quality 10 or higher (mapQ10). However, it may occasionally assign a high mapping
quality to a read with multiple identical best alignments. This reduced its quality to a read with multiple identical best alignments. This reduced its
mapping accuracy. mapping accuracy.
In lack of groud truth for real data, so we took Winnowmap2 mapping as ground In lack of groud truth for real data, we took Winnowmap2 mapping as ground
truth to evaluate other mappers (winno-cmp). Out of 1,378,092 reads with mapQ10 truth to evaluate other mappers (winno-cmp in Table~\ref{tab:1}). Out of 1,378,092 reads with mapQ10
alignments by Winnowmap2, minimap2 v2.22 could map all of them. 118 reads, less alignments by Winnowmap2, minimap2 v2.22 could map all of them. 118 reads, less
than 0.01\% of all reads, were mapped differently by v2.22. 51 of them have than 0.01\% of all reads, were mapped differently by v2.22. 51 of them have
multiple identical best alignments. We believe these are more likely to be multiple identical best alignments. We believe these are more likely to be
Winnowmap2 errors. Most of the remaining 67 (=118-51) reads have multiple Winnowmap2 errors. Most of the remaining 67 (=118-51) reads have multiple
highly similar but not identical alignments. We are not sure what are real highly similar but not identical alignments.
mapping errors. Minimap2 v2.18 is less consistent with 275 differences including 30 unmapped
reads mappable by both Winnowmap2 and v2.22.
The two benchmarks above only evaluate read mappings without variations. For the minimizer rescuing parameter $L$ in Section~\ref{sec:high-occ},
we set its default to 500 such that v2.22 has comparable performance to v2.18 given simulated PacBio and Nanopore human reads.
To see the effect of this parameter on real data, we tried several different $L$ values.
v2.22 gave 99 mapping differences at $L=200$,
118 at $L=500$ (default), 167 at $L=750$ and 224 differences at $L=1000$ in comparison to Winnowmap2.
$L=200$ is 28\% slower than the default while $L=1000$ is 9\% faster.
Changing the default minimizer window size (option ``-w'')
and the initial minimizer occurrence cutoff (option ``-f'')
also affects performance and accuracy to a similar magnitude.
The two benchmarks above only evaluate read mappings when there are no variations between the reads and the reference.
To measure the mapping accuracy in the presence of SVs (sim-sv), we reproduced To measure the mapping accuracy in the presence of SVs (sim-sv), we reproduced
the results by~\citep{Jain2020.11.01.363887}. Minimap2 v2.22 is as good as the results by~\citep{Jain2020.11.01.363887}. Minimap2 v2.22 is as good as
Winnowmap2 now. Note that we were setting the Sniffles mapping quality Winnowmap2 now. Note that we were setting the Sniffles mapping quality
threshold to 10 in consistent with the benchmarks above. If we used the threshold to 10 in consistent with the benchmarks above. If we used the
default threshold 20, v2.22 would miss additional 0.5\% SVs, suggesting default threshold 20, v2.22 would miss additional five SVs (accounting for
minimap2 v2.22 could map variant reads correctly but with conservative mapping 0.5\% of simulated SVs). For four out of these five missing SVs, minimap2 v2.22
quality. This observation is more about the interaction between mappers and mapped more variant reads than Winnowmap2. Sniffles did not call these SVs
callers. Furthermore, the simulation here only considers a simple scenario in because minimap2 tended to give them conservative mapping quality. It is worth
evolution. Non-allelic gene conversions, which happen often in segmental noting that the simulation here only considers a simple scenario in evolution.
Non-allelic gene conversions, which happen often in segmental
duplications~\citep{Harpak:2017aa}, would obscure the optimal mapping duplications~\citep{Harpak:2017aa}, would obscure the optimal mapping
strategies. How much such simple SV simulation informs real-world SV calling strategies. How much such simple SV simulation informs real-world SV calling
remains a question. remains a question.
@@ -204,18 +220,17 @@ remains a question.
To see if minimap2 v2.22 could improve long INDEL alignment, we ran dipcall on To see if minimap2 v2.22 could improve long INDEL alignment, we ran dipcall on
contig-to-reference alignments and focused on INDELs longer than 1kb contig-to-reference alignments and focused on INDELs longer than 1kb
(real-sv-1k). v2.22 is more sensitive at comparable specificity, confirming its (real-sv-1k). v2.22 is more sensitive at comparable specificity, confirming its
advantage in more contiguous alignment. lra is supposed to handle long INDELs advantage in more contiguous alignment. We could not get dipcall to work well with lra,
better, too. However, we could not get lra to work well with dipcall, so did so did not report the numbers.
not report the numbers.
Minimap2 spends most computing time on base alignment. As recent improvements Minimap2 spends most computing time on base alignment. As recent improvements
in v2.22 incur little additional computing and do not change the base alignment in v2.22 incur little additional computing and do not change the base alignment
algorithm, the new version has similar performance to older verions. It is algorithm, the new version has similar performance to older versions. It is
consistently faster than Winnowmap2 by several times. Sometimes simple consistently faster than Winnowmap2 by several times. Sometimes simple
heuristics can be as effective as more sophisticated yet slower solutions. heuristics can be as effective as more sophisticated yet slower solutions.
\section*{Acknowledgements} \section*{Acknowledgements}
We thank Arang Rhie and Chirag Jain for providing motivating examples where We thank Arang Rhie and Chirag Jain for providing motivating examples for which
older minimap2 underperforms. older minimap2 underperforms.
\paragraph{Funding\textcolon} This work is funded by NHGRI grant R01HG010040. \paragraph{Funding\textcolon} This work is funded by NHGRI grant R01HG010040.