mirror of
https://github.com/lh3/minimap2.git
synced 2026-09-26 18:48:11 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
53ce317e59 | ||
|
|
da6947cfa3 | ||
|
|
46d6349af4 | ||
|
|
12a5a5fa3c | ||
|
|
ad18fa490d | ||
|
|
43bfa6199d | ||
|
|
72b9b0e3b6 | ||
|
|
6205fa6f21 | ||
|
|
d676a5314b | ||
|
|
dfc78b39d3 | ||
|
|
7b57c9a619 | ||
|
|
123bc1d91d | ||
|
|
dd18307e66 | ||
|
|
543fa12e68 | ||
|
|
af1a871270 | ||
|
|
2b71181a37 | ||
|
|
0454e6be91 | ||
|
|
33f8157961 | ||
|
|
eecc06086f | ||
|
|
dfea113f28 | ||
|
|
1842d7f5b5 | ||
|
|
f5cfd439ee | ||
|
|
248b43cc47 | ||
|
|
bf72969ab1 | ||
|
|
7b5a601d48 | ||
|
|
405d531100 | ||
|
|
e9607fcd9b | ||
|
|
a465a920ec | ||
|
|
b20839be77 | ||
|
|
209beb9955 | ||
|
|
cfe87f50c1 | ||
|
|
680b971bb0 | ||
|
|
6b0d3c1fa8 | ||
|
|
dc9e3dcf4a | ||
|
|
cc75c12905 | ||
|
|
f159e1c2d3 | ||
|
|
3a375d3436 | ||
|
|
626f10e0d0 | ||
|
|
b997578078 | ||
|
|
ce8a48d715 | ||
|
|
99879e9e75 | ||
|
|
c969d1a1ce | ||
|
|
fcac296c4a | ||
|
|
e420b17496 | ||
|
|
23a846c594 | ||
|
|
8995e2e078 | ||
|
|
ab345e600b | ||
|
|
d003a00d71 | ||
|
|
ae85dcde76 |
@@ -10,10 +10,6 @@ matrix:
|
|||||||
python: "2.7"
|
python: "2.7"
|
||||||
before_install: pip install cython
|
before_install: pip install cython
|
||||||
script: python setup.py build_ext
|
script: python setup.py build_ext
|
||||||
- language: python
|
|
||||||
python: "3.3"
|
|
||||||
before_install: pip install cython
|
|
||||||
script: python setup.py build_ext
|
|
||||||
- language: python
|
- language: python
|
||||||
python: "3.5"
|
python: "3.5"
|
||||||
before_install: pip install cython
|
before_install: pip install cython
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
CFLAGS= -g -Wall -O2 -Wc++-compat
|
CFLAGS= -g -Wall -O2 -Wc++-compat
|
||||||
CPPFLAGS= -DHAVE_KALLOC
|
CPPFLAGS= -DHAVE_KALLOC
|
||||||
INCLUDES=
|
INCLUDES=
|
||||||
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o index.o chain.o align.o hit.o map.o format.o pe.o esterr.o ksw2_ll_sse.o
|
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 ksw2_ll_sse.o
|
||||||
PROG= minimap2
|
PROG= minimap2
|
||||||
PROG_EXTRA= sdust minimap2-lite
|
PROG_EXTRA= sdust minimap2-lite
|
||||||
LIBS= -lm -lz -lpthread
|
LIBS= -lm -lz -lpthread
|
||||||
|
|
||||||
|
ifeq ($(arm_neon),)
|
||||||
ifeq ($(sse2only),)
|
ifeq ($(sse2only),)
|
||||||
OBJS+=ksw2_extz2_sse41.o ksw2_extd2_sse41.o ksw2_exts2_sse41.o ksw2_extz2_sse2.o ksw2_extd2_sse2.o ksw2_exts2_sse2.o ksw2_dispatch.o
|
OBJS+=ksw2_extz2_sse41.o ksw2_extd2_sse41.o ksw2_exts2_sse41.o ksw2_extz2_sse2.o ksw2_extd2_sse2.o ksw2_exts2_sse2.o ksw2_dispatch.o
|
||||||
else
|
else
|
||||||
OBJS+=ksw2_extz2_sse.o ksw2_extd2_sse.o ksw2_exts2_sse.o
|
OBJS+=ksw2_extz2_sse.o ksw2_extd2_sse.o ksw2_exts2_sse.o
|
||||||
endif
|
endif
|
||||||
|
else
|
||||||
|
OBJS+=ksw2_extz2_neon.o ksw2_extd2_neon.o ksw2_exts2_neon.o
|
||||||
|
CFLAGS+=-D_FILE_OFFSET_BITS=64 -mfpu=neon -fsigned-char
|
||||||
|
INCLUDES+=-I sse2neon
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY:all extra clean depend
|
||||||
.SUFFIXES:.c .o
|
.SUFFIXES:.c .o
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@@ -33,6 +40,8 @@ libminimap2.a:$(OBJS)
|
|||||||
sdust:sdust.c getopt.o kalloc.o kalloc.h kdq.h kvec.h kseq.h sdust.h
|
sdust:sdust.c getopt.o kalloc.o kalloc.h kdq.h kvec.h kseq.h sdust.h
|
||||||
$(CC) -D_SDUST_MAIN $(CFLAGS) $< getopt.o kalloc.o -o $@ -lz
|
$(CC) -D_SDUST_MAIN $(CFLAGS) $< getopt.o kalloc.o -o $@ -lz
|
||||||
|
|
||||||
|
# SSE-specific targets on x86/x86_64
|
||||||
|
|
||||||
ksw2_extz2_sse41.o:ksw2_extz2_sse.c ksw2.h kalloc.h
|
ksw2_extz2_sse41.o:ksw2_extz2_sse.c ksw2.h kalloc.h
|
||||||
$(CC) -c -msse4 $(CFLAGS) $(CPPFLAGS) -DKSW_CPU_DISPATCH $(INCLUDES) $< -o $@
|
$(CC) -c -msse4 $(CFLAGS) $(CPPFLAGS) -DKSW_CPU_DISPATCH $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
@@ -54,8 +63,21 @@ ksw2_exts2_sse2.o:ksw2_exts2_sse.c ksw2.h kalloc.h
|
|||||||
ksw2_dispatch.o:ksw2_dispatch.c ksw2.h
|
ksw2_dispatch.o:ksw2_dispatch.c ksw2.h
|
||||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) -DKSW_CPU_DISPATCH $(INCLUDES) $< -o $@
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -DKSW_CPU_DISPATCH $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
# NEON-specific targets on ARM
|
||||||
|
|
||||||
|
ksw2_extz2_neon.o:ksw2_extz2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -DKSW_SSE2_ONLY -D__SSE2__ $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
ksw2_extd2_neon.o:ksw2_extd2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -DKSW_SSE2_ONLY -D__SSE2__ $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
ksw2_exts2_neon.o:ksw2_exts2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) -DKSW_SSE2_ONLY -D__SSE2__ $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
# other non-file targets
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr gmon.out *.o a.out $(PROG) $(PROG_EXTRA) *~ *.a *.dSYM build dist mappy.so mappy.c python/mappy.c mappy.egg*
|
rm -fr gmon.out *.o a.out $(PROG) $(PROG_EXTRA) *~ *.a *.dSYM build dist mappy*.so mappy.c python/mappy.c mappy.egg*
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
(LC_ALL=C; export LC_ALL; makedepend -Y -- $(CFLAGS) $(CPPFLAGS) -- *.c)
|
(LC_ALL=C; export LC_ALL; makedepend -Y -- $(CFLAGS) $(CPPFLAGS) -- *.c)
|
||||||
@@ -65,6 +87,7 @@ depend:
|
|||||||
align.o: minimap.h mmpriv.h bseq.h ksw2.h kalloc.h
|
align.o: minimap.h mmpriv.h bseq.h ksw2.h kalloc.h
|
||||||
bseq.o: bseq.h kvec.h kalloc.h kseq.h
|
bseq.o: bseq.h kvec.h kalloc.h kseq.h
|
||||||
chain.o: minimap.h mmpriv.h bseq.h kalloc.h
|
chain.o: minimap.h mmpriv.h bseq.h kalloc.h
|
||||||
|
esterr.o: mmpriv.h minimap.h bseq.h
|
||||||
example.o: minimap.h kseq.h
|
example.o: minimap.h kseq.h
|
||||||
format.o: kalloc.h mmpriv.h minimap.h bseq.h
|
format.o: kalloc.h mmpriv.h minimap.h bseq.h
|
||||||
getopt.o: getopt.h
|
getopt.o: getopt.h
|
||||||
@@ -75,9 +98,12 @@ ksw2_extd2_sse.o: ksw2.h kalloc.h
|
|||||||
ksw2_exts2_sse.o: ksw2.h kalloc.h
|
ksw2_exts2_sse.o: ksw2.h kalloc.h
|
||||||
ksw2_extz2_sse.o: ksw2.h kalloc.h
|
ksw2_extz2_sse.o: ksw2.h kalloc.h
|
||||||
ksw2_ll_sse.o: ksw2.h kalloc.h
|
ksw2_ll_sse.o: ksw2.h kalloc.h
|
||||||
|
kthread.o: kthread.h
|
||||||
main.o: bseq.h minimap.h mmpriv.h getopt.h
|
main.o: bseq.h minimap.h mmpriv.h getopt.h
|
||||||
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h khash.h
|
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h khash.h
|
||||||
misc.o: minimap.h ksort.h
|
map.o: ksort.h
|
||||||
|
misc.o: mmpriv.h minimap.h bseq.h ksort.h
|
||||||
|
options.o: mmpriv.h minimap.h bseq.h
|
||||||
pe.o: mmpriv.h minimap.h bseq.h kvec.h kalloc.h ksort.h
|
pe.o: mmpriv.h minimap.h bseq.h kvec.h kalloc.h ksort.h
|
||||||
sdust.o: kalloc.h kdq.h kvec.h sdust.h
|
sdust.o: kalloc.h kdq.h kvec.h sdust.h
|
||||||
sketch.o: kvec.h kalloc.h minimap.h
|
sketch.o: kvec.h kalloc.h mmpriv.h minimap.h bseq.h
|
||||||
|
|||||||
@@ -1,3 +1,57 @@
|
|||||||
|
Release 2.8-r672 (1 February 2018)
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Notable changes in this release include:
|
||||||
|
|
||||||
|
* Speed up short-read alignment by ~10%. The overall mapping accuracy stays
|
||||||
|
the same, but the output alignments are not always identical to v2.7 due to
|
||||||
|
unstable sorting employed during chaining. Long-read alignment is not
|
||||||
|
affected by this change as the speedup is short-read specific.
|
||||||
|
|
||||||
|
* Mappy now supports paired-end short-read alignment (#87). Please see
|
||||||
|
python/README.rst for details.
|
||||||
|
|
||||||
|
* Added option --for-only and --rev-only to perform alignment against the
|
||||||
|
forward or the reverse strand of the reference genome only (#91).
|
||||||
|
|
||||||
|
* Alleviated the issue with undesired diagonal alignment in the self mapping
|
||||||
|
mode (#10). Even if the output is not ideal, it should not interfere with
|
||||||
|
other alignments. Fully resolving the issue is intricate and may require
|
||||||
|
additional heuristic thresholds.
|
||||||
|
|
||||||
|
* Enhanced error checking against incorrect input (#92 and #96).
|
||||||
|
|
||||||
|
For long query sequences, minimap2 should output identical alignments to v2.7.
|
||||||
|
|
||||||
|
(2.8: 1 February 2018, r672)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.7-r654 (9 January 2018)
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
This release fixed a bug in the splice mode and added a few minor features:
|
||||||
|
|
||||||
|
* Fixed a bug that occasionally takes an intron as a long deletion in the
|
||||||
|
splice mode. This was caused by wrong backtracking at the last CIGAR
|
||||||
|
operator. The current fix eliminates the error, but it is not optimal in
|
||||||
|
that it often produces a wrong junction when the last operator is an intron.
|
||||||
|
A future version of minimap2 may improve upon this.
|
||||||
|
|
||||||
|
* Support high-end ARM CPUs that implement the NEON instruction set (#81).
|
||||||
|
This enables minimap2 to work on Raspberry Pi 3 and Odroid XU4.
|
||||||
|
|
||||||
|
* Added a C API to construct a minimizer index from a set of C strings (#80).
|
||||||
|
|
||||||
|
* Check scoring specified on the command line (#79). Due to the 8-bit limit,
|
||||||
|
excessively large score penalties fail minimap2.
|
||||||
|
|
||||||
|
For genomic sequences, minimap2 should give identical alignments to v2.6.
|
||||||
|
|
||||||
|
(2.7: 9 January 2018, r654)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Release 2.6-r623 (12 December 2017)
|
Release 2.6-r623 (12 December 2017)
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -65,18 +65,21 @@ Detailed evaluations are available from the [minimap2 preprint][preprint].
|
|||||||
|
|
||||||
### <a name="install"></a>Installation
|
### <a name="install"></a>Installation
|
||||||
|
|
||||||
Minimap2 only works on 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.6/minimap2-2.6_x64-linux.tar.bz2 \
|
curl -L https://github.com/lh3/minimap2/releases/download/v2.8/minimap2-2.8_x64-linux.tar.bz2 \
|
||||||
| tar -jxvf -
|
| tar -jxvf -
|
||||||
./minimap2-2.6_x64-linux/minimap2
|
./minimap2-2.8_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
|
||||||
directory to compile. If you see compilation errors, try `make sse2only=1`
|
directory to compile. If you see compilation errors, try `make sse2only=1`
|
||||||
to disable SSE4 code, which will make minimap2 slightly slower.
|
to disable SSE4 code, which will make minimap2 slightly slower.
|
||||||
|
|
||||||
|
Minimap2 also works with ARM CPUs supporting the NEON instruction sets. To
|
||||||
|
compile, use `make arm_neon=1`.
|
||||||
|
|
||||||
### <a name="general"></a>General usage
|
### <a name="general"></a>General usage
|
||||||
|
|
||||||
Without any options, minimap2 takes a reference database and a query sequence
|
Without any options, minimap2 takes a reference database and a query sequence
|
||||||
@@ -352,12 +355,9 @@ mappy` or [from BioConda][mappyconda] via `conda install -c bioconda mappy`.
|
|||||||
regions where seed positions may be suboptimal. This should not be a big
|
regions where seed positions may be suboptimal. This should not be a big
|
||||||
concern because even the optimal alignment may be wrong in such regions.
|
concern because even the optimal alignment may be wrong in such regions.
|
||||||
|
|
||||||
* Minimap2 requires SSE2 instructions to compile. It is possible to add
|
* Minimap2 requires SSE2 instructions on x86 CPUs or NEON on ARM CPUs. It is
|
||||||
non-SSE2 support, but it would make minimap2 slower by several times.
|
possible to add non-SIMD support, but it would make minimap2 slower by
|
||||||
|
several times.
|
||||||
In general, minimap2 is a young project with most code written since June, 2017.
|
|
||||||
It may have bugs and room for improvements. Bug reports and suggestions are
|
|
||||||
warmly welcomed.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -210,6 +210,13 @@ static void mm_align_pair(void *km, const mm_mapopt_t *opt, int qlen, const uint
|
|||||||
ksw_extz2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, w, zdrop, end_bonus, flag, ez);
|
ksw_extz2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, w, zdrop, end_bonus, flag, ez);
|
||||||
else
|
else
|
||||||
ksw_extd2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->e2, w, zdrop, end_bonus, flag, ez);
|
ksw_extd2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->e2, w, zdrop, end_bonus, flag, ez);
|
||||||
|
if (mm_dbg_flag & MM_DBG_PRINT_ALN_SEQ) {
|
||||||
|
int i;
|
||||||
|
fprintf(stderr, "score=%d, cigar=", ez->score);
|
||||||
|
for (i = 0; i < ez->n_cigar; ++i)
|
||||||
|
fprintf(stderr, "%d%c", ez->cigar[i]>>4, "MIDN"[ez->cigar[i]&0xf]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int mm_get_hplen_back(const mm_idx_t *mi, uint32_t rid, uint32_t x)
|
static inline int mm_get_hplen_back(const mm_idx_t *mi, uint32_t rid, uint32_t x)
|
||||||
@@ -492,6 +499,14 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
re0 = re0 > re1? re0 : re1;
|
re0 = re0 > re1? re0 : re1;
|
||||||
} else re0 = re, qe0 = qe;
|
} else re0 = re, qe0 = qe;
|
||||||
}
|
}
|
||||||
|
if (a[r->as].y & MM_SEED_SELF) {
|
||||||
|
int max_ext = r->qs > r->rs? r->qs - r->rs : r->rs - r->qs;
|
||||||
|
if (r->rs - rs0 > max_ext) rs0 = r->rs - max_ext;
|
||||||
|
if (r->qs - qs0 > max_ext) qs0 = r->qs - max_ext;
|
||||||
|
max_ext = r->qe > r->re? r->qe - r->re : r->re - r->qe;
|
||||||
|
if (re0 - r->re > max_ext) re0 = r->re + max_ext;
|
||||||
|
if (qe0 - r->qe > max_ext) qe0 = r->qe + max_ext;
|
||||||
|
}
|
||||||
|
|
||||||
assert(re0 > rs0);
|
assert(re0 > rs0);
|
||||||
tseq = (uint8_t*)kmalloc(km, re0 - rs0);
|
tseq = (uint8_t*)kmalloc(km, re0 - rs0);
|
||||||
@@ -689,7 +704,7 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
|
|||||||
regs[i].p->trans_strand = opt->flag&MM_F_SPLICE_FOR? 1 : 2;
|
regs[i].p->trans_strand = opt->flag&MM_F_SPLICE_FOR? 1 : 2;
|
||||||
}
|
}
|
||||||
if (r2.cnt > 0) regs = mm_insert_reg(&r2, i, &n_regs, regs);
|
if (r2.cnt > 0) regs = mm_insert_reg(&r2, i, &n_regs, regs);
|
||||||
if (!(opt->flag&MM_F_SPLICE) && !(opt->flag&MM_F_SR) && i > 0) { // don't try inversion alignment for -xsplice or -xsr
|
if (!(opt->flag&(MM_F_SPLICE|MM_F_SR)) && !(opt->flag&(MM_F_FOR_ONLY|MM_F_REV_ONLY)) && i > 0) { // don't try inversion alignment for -xsplice or -xsr, or --for-only/rev-only
|
||||||
if (mm_align1_inv(km, opt, mi, qlen, qseq0, ®s[i-1], ®s[i], &r2, &ez)) {
|
if (mm_align1_inv(km, opt, mi, qlen, qseq0, ®s[i-1], ®s[i], &r2, &ez)) {
|
||||||
regs = mm_insert_reg(&r2, i, &n_regs, regs);
|
regs = mm_insert_reg(&r2, i, &n_regs, regs);
|
||||||
++i; // skip the inserted INV alignment
|
++i; // skip the inserted INV alignment
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#define __STDC_LIMIT_MACROS
|
||||||
#include "bseq.h"
|
#include "bseq.h"
|
||||||
#include "kvec.h"
|
#include "kvec.h"
|
||||||
#include "kseq.h"
|
#include "kseq.h"
|
||||||
@@ -114,10 +115,15 @@ mm_bseq1_t *mm_bseq_read_frag(int n_fp, mm_bseq_file_t **fp, int chunk_size, int
|
|||||||
*n_ = 0;
|
*n_ = 0;
|
||||||
if (n_fp < 1) return 0;
|
if (n_fp < 1) return 0;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
int n_read = 0;
|
||||||
for (i = 0; i < n_fp; ++i)
|
for (i = 0; i < n_fp; ++i)
|
||||||
if (kseq_read(fp[i]->ks) < 0)
|
if (kseq_read(fp[i]->ks) >= 0)
|
||||||
break;
|
++n_read;
|
||||||
if (i != n_fp) break; // some file reaches the end
|
if (n_read < n_fp) {
|
||||||
|
if (n_read > 0)
|
||||||
|
fprintf(stderr, "[W::%s]\033[1;31m query files have different number of records; extra records skipped.\033[0m\n", __func__);
|
||||||
|
break; // some file reaches the end
|
||||||
|
}
|
||||||
if (a.m == 0) kv_resize(mm_bseq1_t, 0, a, 256);
|
if (a.m == 0) kv_resize(mm_bseq1_t, 0, a, 256);
|
||||||
for (i = 0; i < n_fp; ++i) {
|
for (i = 0; i < n_fp; ++i) {
|
||||||
mm_bseq1_t *s;
|
mm_bseq1_t *s;
|
||||||
|
|||||||
@@ -390,8 +390,10 @@ mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int
|
|||||||
for (s = 0; s < n_segs; ++s) {
|
for (s = 0; s < n_segs; ++s) {
|
||||||
regs[s] = mm_gen_regs(km, hash, qlens[s], seg[s].n_u, seg[s].u, seg[s].a);
|
regs[s] = mm_gen_regs(km, hash, qlens[s], seg[s].n_u, seg[s].u, seg[s].a);
|
||||||
n_regs[s] = seg[s].n_u;
|
n_regs[s] = seg[s].n_u;
|
||||||
for (i = 0; i < n_regs[s]; ++i)
|
for (i = 0; i < n_regs[s]; ++i) {
|
||||||
regs[s][i].seg_split = 1;
|
regs[s][i].seg_split = 1;
|
||||||
|
regs[s][i].seg_id = s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return seg;
|
return seg;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#define __STDC_LIMIT_MACROS
|
||||||
#include "kthread.h"
|
#include "kthread.h"
|
||||||
#include "bseq.h"
|
#include "bseq.h"
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
@@ -329,7 +330,7 @@ mm_idx_t *mm_idx_gen(mm_bseq_file_t *fp, int w, int k, int b, int flag, int mini
|
|||||||
return pl.mi;
|
return pl.mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads) // a simpler interface
|
mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads) // a simpler interface; deprecated
|
||||||
{
|
{
|
||||||
mm_bseq_file_t *fp;
|
mm_bseq_file_t *fp;
|
||||||
mm_idx_t *mi;
|
mm_idx_t *mi;
|
||||||
@@ -340,6 +341,49 @@ mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads) //
|
|||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mm_idx_t *mm_idx_str(int w, int k, int is_hpc, int bucket_bits, int n, const char **seq, const char **name)
|
||||||
|
{
|
||||||
|
uint64_t sum_len = 0;
|
||||||
|
mm128_v a = {0,0,0};
|
||||||
|
mm_idx_t *mi;
|
||||||
|
int i, flag = 0;
|
||||||
|
if (n <= 0) return 0;
|
||||||
|
for (i = 0; i < n; ++i) // get the total length
|
||||||
|
sum_len += strlen(seq[i]);
|
||||||
|
if (is_hpc) flag |= MM_I_HPC;
|
||||||
|
if (name == 0) flag |= MM_I_NO_NAME;
|
||||||
|
if (bucket_bits < 0) bucket_bits = 14;
|
||||||
|
mi = mm_idx_init(w, k, bucket_bits, flag);
|
||||||
|
mi->n_seq = n;
|
||||||
|
mi->seq = (mm_idx_seq_t*)kcalloc(mi->km, n, sizeof(mm_idx_seq_t)); // ->seq is allocated from km
|
||||||
|
mi->S = (uint32_t*)calloc((sum_len + 7) / 8, 4);
|
||||||
|
for (i = 0, sum_len = 0; i < n; ++i) {
|
||||||
|
const char *s = seq[i];
|
||||||
|
mm_idx_seq_t *p = &mi->seq[i];
|
||||||
|
uint32_t j;
|
||||||
|
if (name && name[i]) {
|
||||||
|
p->name = (char*)kmalloc(mi->km, strlen(name[i]) + 1);
|
||||||
|
strcpy(p->name, name[i]);
|
||||||
|
}
|
||||||
|
p->offset = sum_len;
|
||||||
|
p->len = strlen(s);
|
||||||
|
for (j = 0; j < p->len; ++j) {
|
||||||
|
int c = seq_nt4_table[(uint8_t)s[j]];
|
||||||
|
uint64_t o = sum_len + j;
|
||||||
|
mm_seq4_set(mi->S, o, c);
|
||||||
|
}
|
||||||
|
sum_len += p->len;
|
||||||
|
if (p->len > 0) {
|
||||||
|
a.n = 0;
|
||||||
|
mm_sketch(0, s, p->len, w, k, i, is_hpc, &a);
|
||||||
|
mm_idx_add(mi, a.n, a.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(a.a);
|
||||||
|
mm_idx_post(mi, 1);
|
||||||
|
return mi;
|
||||||
|
}
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
* index I/O *
|
* index I/O *
|
||||||
*************/
|
*************/
|
||||||
|
|||||||
@@ -39,7 +39,24 @@ typedef struct {
|
|||||||
|
|
||||||
#define KSORT_SWAP(type_t, a, b) { register type_t t=(a); (a)=(b); (b)=t; }
|
#define KSORT_SWAP(type_t, a, b) { register type_t t=(a); (a)=(b); (b)=t; }
|
||||||
|
|
||||||
#define KSORT_INIT(name, type_t, __sort_lt) \
|
#define KSORT_INIT(name, type_t, __sort_lt) \
|
||||||
|
void ks_heapdown_##name(size_t i, size_t n, type_t l[]) \
|
||||||
|
{ \
|
||||||
|
size_t k = i; \
|
||||||
|
type_t tmp = l[i]; \
|
||||||
|
while ((k = (k << 1) + 1) < n) { \
|
||||||
|
if (k != n - 1 && __sort_lt(l[k], l[k+1])) ++k; \
|
||||||
|
if (__sort_lt(l[k], tmp)) break; \
|
||||||
|
l[i] = l[k]; i = k; \
|
||||||
|
} \
|
||||||
|
l[i] = tmp; \
|
||||||
|
} \
|
||||||
|
void ks_heapmake_##name(size_t lsize, type_t l[]) \
|
||||||
|
{ \
|
||||||
|
size_t i; \
|
||||||
|
for (i = (lsize >> 1) - 1; i != (size_t)(-1); --i) \
|
||||||
|
ks_heapdown_##name(i, lsize, l); \
|
||||||
|
} \
|
||||||
type_t ks_ksmall_##name(size_t n, type_t arr[], size_t kk) \
|
type_t ks_ksmall_##name(size_t n, type_t arr[], size_t kk) \
|
||||||
{ \
|
{ \
|
||||||
type_t *low, *high, *k, *ll, *hh, *mid; \
|
type_t *low, *high, *k, *ll, *hh, *mid; \
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ static inline uint32_t *ksw_push_cigar(void *km, int *n_cigar, int *m_cigar, uin
|
|||||||
// bit 0-2: which type gets the max - 0 for H, 1 for E, 2 for F, 3 for \tilde{E} and 4 for \tilde{F}
|
// bit 0-2: which type gets the max - 0 for H, 1 for E, 2 for F, 3 for \tilde{E} and 4 for \tilde{F}
|
||||||
// bit 3/0x08: 1 if a continuation on the E state (bit 5/0x20 for a continuation on \tilde{E})
|
// bit 3/0x08: 1 if a continuation on the E state (bit 5/0x20 for a continuation on \tilde{E})
|
||||||
// bit 4/0x10: 1 if a continuation on the F state (bit 6/0x40 for a continuation on \tilde{F})
|
// bit 4/0x10: 1 if a continuation on the F state (bit 6/0x40 for a continuation on \tilde{F})
|
||||||
static inline void ksw_backtrack(void *km, int is_rot, int is_rev, int with_N, const uint8_t *p, const int *off, const int *off_end, int n_col, int i0, int j0,
|
static inline void ksw_backtrack(void *km, int is_rot, int is_rev, int min_intron_len, const uint8_t *p, const int *off, const int *off_end, int n_col, int i0, int j0,
|
||||||
int *m_cigar_, int *n_cigar_, uint32_t **cigar_)
|
int *m_cigar_, int *n_cigar_, uint32_t **cigar_)
|
||||||
{ // p[] - lower 3 bits: which type gets the max; bit
|
{ // p[] - lower 3 bits: which type gets the max; bit
|
||||||
int n_cigar = 0, m_cigar = *m_cigar_, i = i0, j = j0, r, state = 0;
|
int n_cigar = 0, m_cigar = *m_cigar_, i = i0, j = j0, r, state = 0;
|
||||||
@@ -138,11 +138,11 @@ static inline void ksw_backtrack(void *km, int is_rot, int is_rev, int with_N, c
|
|||||||
if (state == 0) state = tmp & 7; // TODO: probably this line can be merged into the "else if" line right above; not 100% sure
|
if (state == 0) state = tmp & 7; // TODO: probably this line can be merged into the "else if" line right above; not 100% sure
|
||||||
if (force_state >= 0) state = force_state;
|
if (force_state >= 0) state = force_state;
|
||||||
if (state == 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 0, 1), --i, --j; // match
|
if (state == 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 0, 1), --i, --j; // match
|
||||||
else if (state == 1 || (state == 3 && !with_N)) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 2, 1), --i; // deletion
|
else if (state == 1 || (state == 3 && min_intron_len <= 0)) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 2, 1), --i; // deletion
|
||||||
else if (state == 3 && with_N) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 3, 1), --i; // intron
|
else if (state == 3 && min_intron_len > 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 3, 1), --i; // intron
|
||||||
else cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 1, 1), --j; // insertion
|
else cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 1, 1), --j; // insertion
|
||||||
}
|
}
|
||||||
if (i >= 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 2, i + 1); // first deletion
|
if (i >= 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, min_intron_len > 0 && i >= min_intron_len? 3 : 2, i + 1); // first deletion
|
||||||
if (j >= 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 1, j + 1); // first insertion
|
if (j >= 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, 1, j + 1); // first insertion
|
||||||
if (!is_rev)
|
if (!is_rev)
|
||||||
for (i = 0; i < n_cigar>>1; ++i) // reverse CIGAR
|
for (i = 0; i < n_cigar>>1; ++i) // reverse CIGAR
|
||||||
|
|||||||
+2
-2
@@ -367,9 +367,9 @@ void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
if (with_cigar) { // backtrack
|
if (with_cigar) { // backtrack
|
||||||
int rev_cigar = !!(flag & KSW_EZ_REV_CIGAR);
|
int rev_cigar = !!(flag & KSW_EZ_REV_CIGAR);
|
||||||
if (!ez->zdropped && !(flag&KSW_EZ_EXTZ_ONLY))
|
if (!ez->zdropped && !(flag&KSW_EZ_EXTZ_ONLY))
|
||||||
ksw_backtrack(km, 1, rev_cigar, 1, (uint8_t*)p, off, off_end, n_col_*16, tlen-1, qlen-1, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
|
ksw_backtrack(km, 1, rev_cigar, long_thres, (uint8_t*)p, off, off_end, n_col_*16, tlen-1, qlen-1, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
|
||||||
else if (ez->max_t >= 0 && ez->max_q >= 0)
|
else if (ez->max_t >= 0 && ez->max_q >= 0)
|
||||||
ksw_backtrack(km, 1, rev_cigar, 1, (uint8_t*)p, off, off_end, n_col_*16, ez->max_t, ez->max_q, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
|
ksw_backtrack(km, 1, rev_cigar, long_thres, (uint8_t*)p, off, off_end, n_col_*16, ez->max_t, ez->max_q, &ez->m_cigar, &ez->n_cigar, &ez->cigar);
|
||||||
kfree(km, mem2); kfree(km, off);
|
kfree(km, mem2); kfree(km, off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "kthread.h"
|
||||||
|
|
||||||
#if (defined(WIN32) || defined(_WIN32)) && defined(_MSC_VER)
|
#if (defined(WIN32) || defined(_WIN32)) && defined(_MSC_VER)
|
||||||
#define __sync_fetch_and_add(ptr, addend) _InterlockedExchangeAdd((void*)ptr, addend)
|
#define __sync_fetch_and_add(ptr, addend) _InterlockedExchangeAdd((void*)ptr, addend)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
#include "getopt.h"
|
#include "getopt.h"
|
||||||
|
|
||||||
#define MM_VERSION "2.6-r623"
|
#define MM_VERSION "2.8-r672"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -28,7 +28,7 @@ static struct option long_options[] = {
|
|||||||
{ "seed", required_argument, 0, 0 },
|
{ "seed", required_argument, 0, 0 },
|
||||||
{ "no-kalloc", no_argument, 0, 0 },
|
{ "no-kalloc", no_argument, 0, 0 },
|
||||||
{ "print-qname", no_argument, 0, 0 },
|
{ "print-qname", no_argument, 0, 0 },
|
||||||
{ "no-self", no_argument, 0, 0 },
|
{ "no-self", no_argument, 0, 'D' },
|
||||||
{ "print-seeds", no_argument, 0, 0 },
|
{ "print-seeds", no_argument, 0, 0 },
|
||||||
{ "max-chain-skip", required_argument, 0, 0 },
|
{ "max-chain-skip", required_argument, 0, 0 },
|
||||||
{ "min-dp-len", required_argument, 0, 0 },
|
{ "min-dp-len", required_argument, 0, 0 },
|
||||||
@@ -37,14 +37,19 @@ static struct option long_options[] = {
|
|||||||
{ "cost-non-gt-ag", required_argument, 0, 'C' },
|
{ "cost-non-gt-ag", required_argument, 0, 'C' },
|
||||||
{ "no-long-join", no_argument, 0, 0 },
|
{ "no-long-join", no_argument, 0, 0 },
|
||||||
{ "sr", no_argument, 0, 0 },
|
{ "sr", no_argument, 0, 0 },
|
||||||
{ "frag", optional_argument, 0, 0 },
|
{ "frag", required_argument, 0, 0 },
|
||||||
{ "secondary", optional_argument, 0, 0 },
|
{ "secondary", required_argument, 0, 0 },
|
||||||
{ "cs", optional_argument, 0, 0 },
|
{ "cs", optional_argument, 0, 0 },
|
||||||
{ "end-bonus", required_argument, 0, 0 },
|
{ "end-bonus", required_argument, 0, 0 },
|
||||||
{ "no-pairing", no_argument, 0, 0 },
|
{ "no-pairing", no_argument, 0, 0 },
|
||||||
{ "splice-flank", optional_argument, 0, 0 },
|
{ "splice-flank", required_argument, 0, 0 },
|
||||||
{ "idx-no-seq", no_argument, 0, 0 },
|
{ "idx-no-seq", no_argument, 0, 0 },
|
||||||
{ "end-seed-pen", required_argument, 0, 0 }, // 21
|
{ "end-seed-pen", required_argument, 0, 0 }, // 21
|
||||||
|
{ "for-only", no_argument, 0, 0 }, // 22
|
||||||
|
{ "rev-only", no_argument, 0, 0 }, // 23
|
||||||
|
{ "heap-sort", required_argument, 0, 0 }, // 24
|
||||||
|
{ "all-chain", no_argument, 0, 'P' },
|
||||||
|
{ "dual", required_argument, 0, 0 }, // 26
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ "max-intron-len", required_argument, 0, 'G' },
|
{ "max-intron-len", required_argument, 0, 'G' },
|
||||||
{ "version", no_argument, 0, 'V' },
|
{ "version", no_argument, 0, 'V' },
|
||||||
@@ -67,9 +72,22 @@ static inline int64_t mm_parse_num(const char *str)
|
|||||||
return (int64_t)(x + .499);
|
return (int64_t)(x + .499);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void yes_or_no(mm_mapopt_t *opt, int flag, int long_idx, const char *arg, int yes_to_set)
|
||||||
|
{
|
||||||
|
if (yes_to_set) {
|
||||||
|
if (strcmp(arg, "yes") == 0 || strcmp(arg, "y") == 0) opt->flag |= flag;
|
||||||
|
else if (strcmp(arg, "no") == 0 || strcmp(arg, "n") == 0) opt->flag &= ~flag;
|
||||||
|
else fprintf(stderr, "[WARNING]\033[1;31m option '--%s' only accepts 'yes' or 'no'.\033[0m\n", long_options[long_idx].name);
|
||||||
|
} else {
|
||||||
|
if (strcmp(arg, "yes") == 0 || strcmp(arg, "y") == 0) opt->flag &= ~flag;
|
||||||
|
else if (strcmp(arg, "no") == 0 || strcmp(arg, "n") == 0) opt->flag |= flag;
|
||||||
|
else fprintf(stderr, "[WARNING]\033[1;31m option '--%s' only accepts 'yes' or 'no'.\033[0m\n", long_options[long_idx].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
const char *opt_str = "2aSw:k:K:t:r:f:Vv:g:G:I:d:XT:s:x:Hcp:M:n:z:A:B:O:E:m:N:Qu:R:hF:LC:";
|
const char *opt_str = "2aSDw:k:K:t:r:f:Vv:g:G:I:d:XT:s:x:Hcp:M:n:z:A:B:O:E:m:N:Qu:R:hF:LC:";
|
||||||
mm_mapopt_t opt;
|
mm_mapopt_t opt;
|
||||||
mm_idxopt_t ipt;
|
mm_idxopt_t ipt;
|
||||||
int i, c, n_threads = 3, long_idx;
|
int i, c, n_threads = 3, long_idx;
|
||||||
@@ -108,7 +126,9 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 'p') opt.pri_ratio = atof(optarg);
|
else if (c == 'p') opt.pri_ratio = atof(optarg);
|
||||||
else if (c == 'M') opt.mask_level = atof(optarg);
|
else if (c == 'M') opt.mask_level = atof(optarg);
|
||||||
else if (c == 'c') opt.flag |= MM_F_OUT_CG | MM_F_CIGAR;
|
else if (c == 'c') opt.flag |= MM_F_OUT_CG | MM_F_CIGAR;
|
||||||
else if (c == 'X') opt.flag |= MM_F_AVA | MM_F_NO_SELF;
|
else if (c == 'D') opt.flag |= MM_F_NO_DIAG;
|
||||||
|
else if (c == 'P') opt.flag |= MM_F_ALL_CHAINS;
|
||||||
|
else if (c == 'X') opt.flag |= MM_F_ALL_CHAINS | MM_F_NO_DIAG | MM_F_NO_DUAL | MM_F_NO_LJOIN; // -D -P --no-long-join --dual=no
|
||||||
else if (c == 'a') opt.flag |= MM_F_OUT_SAM | MM_F_CIGAR;
|
else if (c == 'a') opt.flag |= MM_F_OUT_SAM | MM_F_CIGAR;
|
||||||
else if (c == 'Q') opt.flag |= MM_F_NO_QUAL;
|
else if (c == 'Q') opt.flag |= MM_F_NO_QUAL;
|
||||||
else if (c == 'Y') opt.flag |= MM_F_SOFTCLIP;
|
else if (c == 'Y') opt.flag |= MM_F_SOFTCLIP;
|
||||||
@@ -130,11 +150,10 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 0 && long_idx == 2) opt.seed = atoi(optarg); // --seed
|
else if (c == 0 && long_idx == 2) opt.seed = atoi(optarg); // --seed
|
||||||
else if (c == 0 && long_idx == 3) mm_dbg_flag |= MM_DBG_NO_KALLOC; // --no-kalloc
|
else if (c == 0 && long_idx == 3) mm_dbg_flag |= MM_DBG_NO_KALLOC; // --no-kalloc
|
||||||
else if (c == 0 && long_idx == 4) mm_dbg_flag |= MM_DBG_PRINT_QNAME; // --print-qname
|
else if (c == 0 && long_idx == 4) mm_dbg_flag |= MM_DBG_PRINT_QNAME; // --print-qname
|
||||||
else if (c == 0 && long_idx == 5) opt.flag |= MM_F_NO_SELF; // --no-self
|
|
||||||
else if (c == 0 && long_idx == 6) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_SEED, n_threads = 1; // --print-seed
|
else if (c == 0 && long_idx == 6) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_SEED, n_threads = 1; // --print-seed
|
||||||
else if (c == 0 && long_idx == 7) opt.max_chain_skip = atoi(optarg); // --max-chain-skip
|
else if (c == 0 && long_idx == 7) opt.max_chain_skip = atoi(optarg); // --max-chain-skip
|
||||||
else if (c == 0 && long_idx == 8) opt.min_ksw_len = atoi(optarg); // --min-dp-len
|
else if (c == 0 && long_idx == 8) opt.min_ksw_len = atoi(optarg); // --min-dp-len
|
||||||
else if (c == 0 && long_idx == 9) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_ALN_SEQ; // --print-aln-seq
|
else if (c == 0 && long_idx == 9) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_ALN_SEQ, n_threads = 1; // --print-aln-seq
|
||||||
else if (c == 0 && long_idx ==10) opt.flag |= MM_F_SPLICE; // --splice
|
else if (c == 0 && long_idx ==10) opt.flag |= MM_F_SPLICE; // --splice
|
||||||
else if (c == 0 && long_idx ==12) opt.flag |= MM_F_NO_LJOIN; // --no-long-join
|
else if (c == 0 && long_idx ==12) opt.flag |= MM_F_NO_LJOIN; // --no-long-join
|
||||||
else if (c == 0 && long_idx ==13) opt.flag |= MM_F_SR; // --sr
|
else if (c == 0 && long_idx ==13) opt.flag |= MM_F_SR; // --sr
|
||||||
@@ -142,14 +161,12 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 0 && long_idx ==18) opt.flag |= MM_F_INDEPEND_SEG; // --no-pairing
|
else if (c == 0 && long_idx ==18) opt.flag |= MM_F_INDEPEND_SEG; // --no-pairing
|
||||||
else if (c == 0 && long_idx ==20) ipt.flag |= MM_I_NO_SEQ; // --idx-no-seq
|
else if (c == 0 && long_idx ==20) ipt.flag |= MM_I_NO_SEQ; // --idx-no-seq
|
||||||
else if (c == 0 && long_idx ==21) opt.anchor_ext_shift = atoi(optarg); // --end-seed-pen
|
else if (c == 0 && long_idx ==21) opt.anchor_ext_shift = atoi(optarg); // --end-seed-pen
|
||||||
|
else if (c == 0 && long_idx ==22) opt.flag |= MM_F_FOR_ONLY; // --for-only
|
||||||
|
else if (c == 0 && long_idx ==23) opt.flag |= MM_F_REV_ONLY; // --rev-only
|
||||||
else if (c == 0 && long_idx == 14) { // --frag
|
else if (c == 0 && long_idx == 14) { // --frag
|
||||||
if (optarg == 0 || strcmp(optarg, "yes") == 0 || strcmp(optarg, "y") == 0)
|
yes_or_no(&opt, MM_F_FRAG_MODE, long_idx, optarg, 1);
|
||||||
opt.flag |= MM_F_FRAG_MODE;
|
|
||||||
else opt.flag &= ~MM_F_FRAG_MODE;
|
|
||||||
} else if (c == 0 && long_idx == 15) { // --secondary
|
} else if (c == 0 && long_idx == 15) { // --secondary
|
||||||
if (optarg == 0 || strcmp(optarg, "yes") == 0 || strcmp(optarg, "y") == 0)
|
yes_or_no(&opt, MM_F_NO_PRINT_2ND, long_idx, optarg, 0);
|
||||||
opt.flag &= ~MM_F_NO_PRINT_2ND;
|
|
||||||
else opt.flag |= MM_F_NO_PRINT_2ND;
|
|
||||||
} else if (c == 0 && long_idx == 16) { // --cs
|
} else if (c == 0 && long_idx == 16) { // --cs
|
||||||
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR;
|
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR;
|
||||||
if (optarg == 0 || strcmp(optarg, "short") == 0) {
|
if (optarg == 0 || strcmp(optarg, "short") == 0) {
|
||||||
@@ -162,9 +179,11 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "[WARNING]\033[1;31m --cs only takes 'short' or 'long'. Invalid values are assumed to be 'short'.\033[0m\n");
|
fprintf(stderr, "[WARNING]\033[1;31m --cs only takes 'short' or 'long'. Invalid values are assumed to be 'short'.\033[0m\n");
|
||||||
}
|
}
|
||||||
} else if (c == 0 && long_idx == 19) { // --splice-flank
|
} else if (c == 0 && long_idx == 19) { // --splice-flank
|
||||||
if (optarg == 0 || strcmp(optarg, "yes") == 0 || strcmp(optarg, "y") == 0)
|
yes_or_no(&opt, MM_F_SPLICE_FLANK, long_idx, optarg, 1);
|
||||||
opt.flag |= MM_F_SPLICE_FLANK;
|
} else if (c == 0 && long_idx == 24) { // --heap-sort
|
||||||
else opt.flag &= ~MM_F_SPLICE_FLANK;
|
yes_or_no(&opt, MM_F_HEAP_SORT, long_idx, optarg, 1);
|
||||||
|
} else if (c == 0 && long_idx == 26) { // --dual
|
||||||
|
yes_or_no(&opt, MM_F_NO_DUAL, long_idx, optarg, 0);
|
||||||
} else if (c == 'S') {
|
} else if (c == 'S') {
|
||||||
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR | MM_F_OUT_CS_LONG;
|
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR | MM_F_OUT_CS_LONG;
|
||||||
if (mm_verbose >= 2)
|
if (mm_verbose >= 2)
|
||||||
@@ -202,6 +221,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (!fnw && !(opt.flag&MM_F_CIGAR))
|
if (!fnw && !(opt.flag&MM_F_CIGAR))
|
||||||
ipt.flag |= MM_I_NO_SEQ;
|
ipt.flag |= MM_I_NO_SEQ;
|
||||||
|
if (mm_check_opt(&ipt, &opt) < 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (argc == optind || fp_help == stdout) {
|
if (argc == optind || fp_help == stdout) {
|
||||||
fprintf(fp_help, "Usage: minimap2 [options] <target.fa>|<target.idx> [query.fa] [...]\n");
|
fprintf(fp_help, "Usage: minimap2 [options] <target.fa>|<target.idx> [query.fa] [...]\n");
|
||||||
@@ -250,14 +271,18 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " map-ont: -k15 (Oxford Nanopore vs reference mapping)\n");
|
fprintf(fp_help, " map-ont: -k15 (Oxford Nanopore vs reference mapping)\n");
|
||||||
fprintf(fp_help, " asm5: -k19 -w19 -A1 -B19 -O39,81 -E3,1 -s200 -z200 (asm to ref mapping; break at 5%% div.)\n");
|
fprintf(fp_help, " asm5: -k19 -w19 -A1 -B19 -O39,81 -E3,1 -s200 -z200 (asm to ref mapping; break at 5%% div.)\n");
|
||||||
fprintf(fp_help, " asm10: -k19 -w19 -A1 -B9 -O16,41 -E2,1 -s200 -z200 (asm to ref mapping; break at 10%% div.)\n");
|
fprintf(fp_help, " asm10: -k19 -w19 -A1 -B9 -O16,41 -E2,1 -s200 -z200 (asm to ref mapping; break at 10%% div.)\n");
|
||||||
fprintf(fp_help, " ava-pb: -Hk19 -w5 -Xp0 -m100 -g10000 --max-chain-skip 25 (PacBio read overlap)\n");
|
fprintf(fp_help, " ava-pb: -Hk19 -Xw5 -m100 -g10000 --max-chain-skip 25 (PacBio read overlap)\n");
|
||||||
fprintf(fp_help, " ava-ont: -k15 -w5 -Xp0 -m100 -g10000 --max-chain-skip 25 (ONT read overlap)\n");
|
fprintf(fp_help, " ava-ont: -k15 -Xw5 -m100 -g10000 --max-chain-skip 25 (ONT read overlap)\n");
|
||||||
fprintf(fp_help, " splice: long-read spliced alignment (see minimap2.1 for details)\n");
|
fprintf(fp_help, " splice: long-read spliced alignment (see minimap2.1 for details)\n");
|
||||||
fprintf(fp_help, " sr: short single-end reads without splicing (see minimap2.1 for details)\n");
|
fprintf(fp_help, " sr: short single-end reads without splicing (see minimap2.1 for details)\n");
|
||||||
fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of command-line options.\n");
|
fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of command-line options.\n");
|
||||||
return fp_help == stdout? 0 : 1;
|
return fp_help == stdout? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((opt.flag & MM_F_SR) && argc - optind > 3) {
|
||||||
|
fprintf(stderr, "[ERROR] incorrect input: in the sr mode, please specify no more than two query files.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
idx_rdr = mm_idx_reader_open(argv[optind], &ipt, fnw);
|
idx_rdr = mm_idx_reader_open(argv[optind], &ipt, fnw);
|
||||||
if (idx_rdr == 0) {
|
if (idx_rdr == 0) {
|
||||||
fprintf(stderr, "[ERROR] failed to open file '%s'\n", argv[optind]);
|
fprintf(stderr, "[ERROR] failed to open file '%s'\n", argv[optind]);
|
||||||
|
|||||||
@@ -9,119 +9,6 @@
|
|||||||
#include "bseq.h"
|
#include "bseq.h"
|
||||||
#include "khash.h"
|
#include "khash.h"
|
||||||
|
|
||||||
void mm_mapopt_init(mm_mapopt_t *opt)
|
|
||||||
{
|
|
||||||
memset(opt, 0, sizeof(mm_mapopt_t));
|
|
||||||
opt->seed = 11;
|
|
||||||
opt->mid_occ_frac = 2e-4f;
|
|
||||||
opt->sdust_thres = 0; // no SDUST masking
|
|
||||||
|
|
||||||
opt->min_cnt = 3;
|
|
||||||
opt->min_chain_score = 40;
|
|
||||||
opt->bw = 500;
|
|
||||||
opt->max_gap = 5000;
|
|
||||||
opt->max_gap_ref = -1;
|
|
||||||
opt->max_chain_skip = 25;
|
|
||||||
|
|
||||||
opt->mask_level = 0.5f;
|
|
||||||
opt->pri_ratio = 0.8f;
|
|
||||||
opt->best_n = 5;
|
|
||||||
|
|
||||||
opt->max_join_long = 20000;
|
|
||||||
opt->max_join_short = 2000;
|
|
||||||
opt->min_join_flank_sc = 1000;
|
|
||||||
|
|
||||||
opt->a = 2, opt->b = 4, opt->q = 4, opt->e = 2, opt->q2 = 24, opt->e2 = 1;
|
|
||||||
opt->zdrop = 400;
|
|
||||||
opt->end_bonus = -1;
|
|
||||||
opt->min_dp_max = opt->min_chain_score * opt->a;
|
|
||||||
opt->min_ksw_len = 200;
|
|
||||||
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
|
|
||||||
opt->mini_batch_size = 500000000;
|
|
||||||
|
|
||||||
opt->pe_ori = 0; // FF
|
|
||||||
opt->pe_bonus = 33;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mm_mapopt_update(mm_mapopt_t *opt, const mm_idx_t *mi)
|
|
||||||
{
|
|
||||||
if ((opt->flag & MM_F_SPLICE_FOR) && (opt->flag & MM_F_SPLICE_REV))
|
|
||||||
opt->flag |= MM_F_SPLICE;
|
|
||||||
if (opt->mid_occ <= 0)
|
|
||||||
opt->mid_occ = mm_idx_cal_max_occ(mi, opt->mid_occ_frac);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mm_mapopt_max_intron_len(mm_mapopt_t *opt, int max_intron_len)
|
|
||||||
{
|
|
||||||
if ((opt->flag & MM_F_SPLICE) && max_intron_len > 0)
|
|
||||||
opt->max_gap_ref = opt->bw = max_intron_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
|
||||||
{
|
|
||||||
if (preset == 0) {
|
|
||||||
mm_idxopt_init(io);
|
|
||||||
mm_mapopt_init(mo);
|
|
||||||
} else if (strcmp(preset, "ava-ont") == 0) {
|
|
||||||
io->flag = 0, io->k = 15, io->w = 5;
|
|
||||||
mo->flag |= MM_F_AVA | MM_F_NO_SELF;
|
|
||||||
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
|
|
||||||
} else if (strcmp(preset, "ava-pb") == 0) {
|
|
||||||
io->flag |= MM_I_HPC, io->k = 19, io->w = 5;
|
|
||||||
mo->flag |= MM_F_AVA | MM_F_NO_SELF;
|
|
||||||
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
|
|
||||||
} else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
|
|
||||||
io->flag |= MM_I_HPC, io->k = 19;
|
|
||||||
} else if (strcmp(preset, "map-ont") == 0) {
|
|
||||||
io->flag = 0, io->k = 15;
|
|
||||||
} else if (strcmp(preset, "asm5") == 0) {
|
|
||||||
io->flag = 0, io->k = 19, io->w = 19;
|
|
||||||
mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = 200;
|
|
||||||
mo->min_dp_max = 200;
|
|
||||||
mo->best_n = 50;
|
|
||||||
} else if (strcmp(preset, "asm10") == 0) {
|
|
||||||
io->flag = 0, io->k = 19, io->w = 19;
|
|
||||||
mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = 200;
|
|
||||||
mo->min_dp_max = 200;
|
|
||||||
mo->best_n = 50;
|
|
||||||
} else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) {
|
|
||||||
io->flag = 0, io->k = 21, io->w = 11;
|
|
||||||
mo->flag |= MM_F_SR | MM_F_FRAG_MODE | MM_F_NO_PRINT_2ND | MM_F_2_IO_THREADS;
|
|
||||||
mo->pe_ori = 0<<1|1; // FR
|
|
||||||
mo->a = 2, mo->b = 8, mo->q = 12, mo->e = 2, mo->q2 = 24, mo->e2 = 1;
|
|
||||||
mo->zdrop = 100;
|
|
||||||
mo->end_bonus = 10;
|
|
||||||
mo->max_frag_len = 800;
|
|
||||||
mo->max_gap = 100;
|
|
||||||
mo->bw = 100;
|
|
||||||
mo->pri_ratio = 0.5f;
|
|
||||||
mo->min_cnt = 2;
|
|
||||||
mo->min_chain_score = 25;
|
|
||||||
mo->min_dp_max = 40;
|
|
||||||
mo->best_n = 20;
|
|
||||||
mo->mid_occ = 1000;
|
|
||||||
mo->max_occ = 5000;
|
|
||||||
mo->mini_batch_size = 50000000;
|
|
||||||
} else if (strcmp(preset, "splice") == 0 || strcmp(preset, "cdna") == 0) {
|
|
||||||
io->flag = 0, io->k = 15, io->w = 5;
|
|
||||||
mo->flag |= MM_F_SPLICE | MM_F_SPLICE_FOR | MM_F_SPLICE_REV | MM_F_SPLICE_FLANK;
|
|
||||||
mo->max_gap = 2000, mo->max_gap_ref = mo->bw = 200000;
|
|
||||||
mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0;
|
|
||||||
mo->noncan = 9;
|
|
||||||
mo->zdrop = 200;
|
|
||||||
} else return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t n;
|
|
||||||
uint32_t qpos;
|
|
||||||
uint32_t seg_id;
|
|
||||||
const uint64_t *cr;
|
|
||||||
} mm_match_t;
|
|
||||||
|
|
||||||
struct mm_tbuf_s {
|
struct mm_tbuf_s {
|
||||||
void *km;
|
void *km;
|
||||||
};
|
};
|
||||||
@@ -181,88 +68,189 @@ static void collect_minimizers(void *km, const mm_mapopt_t *opt, const mm_idx_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ, const mm_idx_t *mi, const char *qname, const mm128_v *mv, int qlen, int64_t *n_a, int *rep_len,
|
#include "ksort.h"
|
||||||
int *n_mini_pos, uint64_t **mini_pos)
|
#define heap_lt(a, b) ((a).x > (b).x)
|
||||||
{
|
KSORT_INIT(heap, mm128_t, heap_lt)
|
||||||
int rep_st = 0, rep_en = 0, i;
|
|
||||||
mm_match_t *m;
|
|
||||||
mm128_t *a;
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t n;
|
||||||
|
uint32_t q_pos, q_span;
|
||||||
|
uint32_t seg_id:31, is_tandem:1;
|
||||||
|
const uint64_t *cr;
|
||||||
|
} mm_match_t;
|
||||||
|
|
||||||
|
static mm_match_t *collect_matches(void *km, int *_n_m, int max_occ, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos)
|
||||||
|
{
|
||||||
|
int i, rep_st = 0, rep_en = 0, n_m;
|
||||||
|
mm_match_t *m;
|
||||||
*n_mini_pos = 0;
|
*n_mini_pos = 0;
|
||||||
*mini_pos = (uint64_t*)kmalloc(km, mv->n * sizeof(uint64_t));
|
*mini_pos = (uint64_t*)kmalloc(km, mv->n * sizeof(uint64_t));
|
||||||
m = (mm_match_t*)kmalloc(km, mv->n * sizeof(mm_match_t));
|
m = (mm_match_t*)kmalloc(km, mv->n * sizeof(mm_match_t));
|
||||||
for (i = 0; i < mv->n; ++i) {
|
for (i = n_m = 0, *rep_len = 0, *n_a = 0; i < mv->n; ++i) {
|
||||||
|
const uint64_t *cr;
|
||||||
|
mm128_t *p = &mv->a[i];
|
||||||
|
uint32_t q_pos = (uint32_t)p->y, q_span = p->x & 0xff;
|
||||||
int t;
|
int t;
|
||||||
mm128_t *p = &mv->a[i];
|
cr = mm_idx_get(mi, p->x>>8, &t);
|
||||||
m[i].qpos = (uint32_t)p->y;
|
if (t >= max_occ) {
|
||||||
m[i].cr = mm_idx_get(mi, p->x>>8, &t);
|
int en = (q_pos >> 1) + 1, st = en - q_span;
|
||||||
m[i].n = t;
|
|
||||||
m[i].seg_id = p->y >> 32;
|
|
||||||
}
|
|
||||||
for (i = 0, *n_a = 0; i < mv->n; ++i) // find the length of a[]
|
|
||||||
if (m[i].n < max_occ) *n_a += m[i].n;
|
|
||||||
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
|
||||||
for (i = *rep_len = 0, *n_a = 0; i < mv->n; ++i) {
|
|
||||||
mm128_t *p = &mv->a[i];
|
|
||||||
mm_match_t *q = &m[i];
|
|
||||||
const uint64_t *r = q->cr;
|
|
||||||
int k, q_span = p->x & 0xff, is_tandem = 0;
|
|
||||||
if (q->n >= max_occ) {
|
|
||||||
int en = (q->qpos>>1) + 1, st = en - q_span;
|
|
||||||
if (st > rep_en) {
|
if (st > rep_en) {
|
||||||
*rep_len += rep_en - rep_st;
|
*rep_len += rep_en - rep_st;
|
||||||
rep_st = st, rep_en = en;
|
rep_st = st, rep_en = en;
|
||||||
} else rep_en = en;
|
} else rep_en = en;
|
||||||
continue;
|
} else {
|
||||||
}
|
mm_match_t *q = &m[n_m++];
|
||||||
(*mini_pos)[(*n_mini_pos)++] = (uint64_t)q_span<<32 | q->qpos>>1;
|
q->q_pos = q_pos, q->q_span = q_span, q->cr = cr, q->n = t, q->seg_id = p->y >> 32;
|
||||||
if (i > 0 && p->x>>8 == mv->a[i - 1].x>>8) is_tandem = 1;
|
q->is_tandem = 0;
|
||||||
if (i < mv->n - 1 && p->x>>8 == mv->a[i + 1].x>>8) is_tandem = 1;
|
if (i > 0 && p->x>>8 == mv->a[i - 1].x>>8) q->is_tandem = 1;
|
||||||
for (k = 0; k < q->n; ++k) {
|
if (i < mv->n - 1 && p->x>>8 == mv->a[i + 1].x>>8) q->is_tandem = 1;
|
||||||
int32_t rpos = (uint32_t)r[k] >> 1;
|
*n_a += q->n;
|
||||||
mm128_t *p;
|
(*mini_pos)[(*n_mini_pos)++] = (uint64_t)q_span<<32 | q_pos>>1;
|
||||||
if (qname && (opt->flag&(MM_F_NO_SELF|MM_F_AVA))) {
|
|
||||||
const char *tname = mi->seq[r[k]>>32].name;
|
|
||||||
int cmp;
|
|
||||||
cmp = strcmp(qname, tname);
|
|
||||||
if ((opt->flag&MM_F_NO_SELF) && cmp == 0 && rpos == (q->qpos>>1)) // avoid the diagonal
|
|
||||||
continue;
|
|
||||||
if ((opt->flag&MM_F_AVA) && cmp > 0) // all-vs-all mode: map once
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
p = &a[(*n_a)++];
|
|
||||||
if ((r[k]&1) == (q->qpos&1)) { // forward strand
|
|
||||||
p->x = (r[k]&0xffffffff00000000ULL) | rpos;
|
|
||||||
p->y = (uint64_t)q_span << 32 | q->qpos >> 1;
|
|
||||||
} else { // reverse strand
|
|
||||||
p->x = 1ULL<<63 | (r[k]&0xffffffff00000000ULL) | rpos;
|
|
||||||
p->y = (uint64_t)q_span << 32 | (qlen - ((q->qpos>>1) + 1 - q_span) - 1);
|
|
||||||
}
|
|
||||||
p->y |= (uint64_t)q->seg_id << MM_SEED_SEG_SHIFT;
|
|
||||||
if (is_tandem) p->y |= MM_SEED_TANDEM;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*rep_len += rep_en - rep_st;
|
*rep_len += rep_en - rep_st;
|
||||||
|
*_n_m = n_m;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int skip_seed(int flag, uint64_t r, const mm_match_t *q, const char *qname, int qlen, const mm_idx_t *mi, int *is_self)
|
||||||
|
{
|
||||||
|
*is_self = 0;
|
||||||
|
if (qname && (flag & (MM_F_NO_DIAG|MM_F_NO_DUAL))) {
|
||||||
|
const mm_idx_seq_t *s = &mi->seq[r>>32];
|
||||||
|
int cmp;
|
||||||
|
cmp = strcmp(qname, s->name);
|
||||||
|
if ((flag&MM_F_NO_DIAG) && cmp == 0 && s->len == qlen) {
|
||||||
|
if ((uint32_t)r>>1 == (q->q_pos>>1)) return 1; // avoid the diagnonal anchors
|
||||||
|
if ((r&1) == (q->q_pos&1)) *is_self = 1; // this flag is used to avoid spurious extension on self chain
|
||||||
|
}
|
||||||
|
if ((flag&MM_F_NO_DUAL) && cmp > 0) // all-vs-all mode: map once
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (flag & (MM_F_FOR_ONLY|MM_F_REV_ONLY)) {
|
||||||
|
if ((r&1) == (q->q_pos&1)) { // forward strand
|
||||||
|
if (flag & MM_F_REV_ONLY) return 1;
|
||||||
|
} else {
|
||||||
|
if (flag & MM_F_FOR_ONLY) return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mm128_t *collect_seed_hits_heap(void *km, const mm_mapopt_t *opt, int max_occ, const mm_idx_t *mi, const char *qname, const mm128_v *mv, int qlen, int64_t *n_a, int *rep_len,
|
||||||
|
int *n_mini_pos, uint64_t **mini_pos)
|
||||||
|
{
|
||||||
|
int i, n_m, heap_size = 0;
|
||||||
|
int64_t j, n_for = 0, n_rev = 0;
|
||||||
|
mm_match_t *m;
|
||||||
|
mm128_t *a, *heap;
|
||||||
|
|
||||||
|
m = collect_matches(km, &n_m, max_occ, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
||||||
|
|
||||||
|
heap = (mm128_t*)kmalloc(km, n_m * sizeof(mm128_t));
|
||||||
|
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
||||||
|
|
||||||
|
for (i = 0, heap_size = 0; i < n_m; ++i) {
|
||||||
|
if (m[i].n > 0) {
|
||||||
|
heap[heap_size].x = m[i].cr[0];
|
||||||
|
heap[heap_size].y = (uint64_t)i<<32;
|
||||||
|
++heap_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ks_heapmake_heap(heap_size, heap);
|
||||||
|
while (heap_size > 0) {
|
||||||
|
mm_match_t *q = &m[heap->y>>32];
|
||||||
|
mm128_t *p;
|
||||||
|
uint64_t r = heap->x;
|
||||||
|
int32_t is_self, rpos = (uint32_t)r >> 1;
|
||||||
|
if (skip_seed(opt->flag, r, q, qname, qlen, mi, &is_self)) continue;
|
||||||
|
if ((r&1) == (q->q_pos&1)) { // forward strand
|
||||||
|
p = &a[n_for++];
|
||||||
|
p->x = (r&0xffffffff00000000ULL) | rpos;
|
||||||
|
p->y = (uint64_t)q->q_span << 32 | q->q_pos >> 1;
|
||||||
|
} else { // reverse strand
|
||||||
|
p = &a[(*n_a) - (++n_rev)];
|
||||||
|
p->x = 1ULL<<63 | (r&0xffffffff00000000ULL) | rpos;
|
||||||
|
p->y = (uint64_t)q->q_span << 32 | (qlen - ((q->q_pos>>1) + 1 - q->q_span) - 1);
|
||||||
|
}
|
||||||
|
p->y |= (uint64_t)q->seg_id << MM_SEED_SEG_SHIFT;
|
||||||
|
if (q->is_tandem) p->y |= MM_SEED_TANDEM;
|
||||||
|
if (is_self) p->y |= MM_SEED_SELF;
|
||||||
|
// update the heap
|
||||||
|
if ((uint32_t)heap->y < q->n - 1) {
|
||||||
|
++heap[0].y;
|
||||||
|
heap[0].x = m[heap[0].y>>32].cr[(uint32_t)heap[0].y];
|
||||||
|
} else {
|
||||||
|
heap[0] = heap[heap_size - 1];
|
||||||
|
--heap_size;
|
||||||
|
}
|
||||||
|
ks_heapdown_heap(0, heap_size, heap);
|
||||||
|
}
|
||||||
kfree(km, m);
|
kfree(km, m);
|
||||||
|
kfree(km, heap);
|
||||||
|
|
||||||
|
// reverse anchors on the reverse strand, as they are in the descending order
|
||||||
|
for (j = 0; j < n_rev>>1; ++j) {
|
||||||
|
mm128_t t = a[(*n_a) - 1 - j];
|
||||||
|
a[(*n_a) - 1 - j] = a[(*n_a) - (n_rev - j)];
|
||||||
|
a[(*n_a) - (n_rev - j)] = t;
|
||||||
|
}
|
||||||
|
if (*n_a > n_for + n_rev) {
|
||||||
|
memmove(a + n_for, a + (*n_a) - n_rev, n_rev * sizeof(mm128_t));
|
||||||
|
*n_a = n_for + n_rev;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ, const mm_idx_t *mi, const char *qname, const mm128_v *mv, int qlen, int64_t *n_a, int *rep_len,
|
||||||
|
int *n_mini_pos, uint64_t **mini_pos)
|
||||||
|
{
|
||||||
|
int i, k, n_m;
|
||||||
|
mm_match_t *m;
|
||||||
|
mm128_t *a;
|
||||||
|
m = collect_matches(km, &n_m, max_occ, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
||||||
|
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
||||||
|
for (i = 0, *n_a = 0; i < n_m; ++i) {
|
||||||
|
mm_match_t *q = &m[i];
|
||||||
|
const uint64_t *r = q->cr;
|
||||||
|
for (k = 0; k < q->n; ++k) {
|
||||||
|
int32_t is_self, rpos = (uint32_t)r[k] >> 1;
|
||||||
|
mm128_t *p;
|
||||||
|
if (skip_seed(opt->flag, r[k], q, qname, qlen, mi, &is_self)) continue;
|
||||||
|
p = &a[(*n_a)++];
|
||||||
|
if ((r[k]&1) == (q->q_pos&1)) { // forward strand
|
||||||
|
p->x = (r[k]&0xffffffff00000000ULL) | rpos;
|
||||||
|
p->y = (uint64_t)q->q_span << 32 | q->q_pos >> 1;
|
||||||
|
} else { // reverse strand
|
||||||
|
p->x = 1ULL<<63 | (r[k]&0xffffffff00000000ULL) | rpos;
|
||||||
|
p->y = (uint64_t)q->q_span << 32 | (qlen - ((q->q_pos>>1) + 1 - q->q_span) - 1);
|
||||||
|
}
|
||||||
|
p->y |= (uint64_t)q->seg_id << MM_SEED_SEG_SHIFT;
|
||||||
|
if (q->is_tandem) p->y |= MM_SEED_TANDEM;
|
||||||
|
if (is_self) p->y |= MM_SEED_SELF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kfree(km, m);
|
||||||
|
radix_sort_128x(a, a + (*n_a));
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void chain_post(const mm_mapopt_t *opt, int max_chain_gap_ref, const mm_idx_t *mi, void *km, int qlen, int n_segs, const int *qlens, int *n_regs, mm_reg1_t *regs, mm128_t *a)
|
static void chain_post(const mm_mapopt_t *opt, int max_chain_gap_ref, const mm_idx_t *mi, void *km, int qlen, int n_segs, const int *qlens, int *n_regs, mm_reg1_t *regs, mm128_t *a)
|
||||||
{
|
{
|
||||||
if (!(opt->flag & MM_F_AVA)) { // don't choose primary mapping(s) for read overlap
|
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
|
||||||
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
|
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
|
||||||
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, 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);
|
||||||
if (!(opt->flag & MM_F_SPLICE) && !(opt->flag & MM_F_SR) && !(opt->flag & MM_F_NO_LJOIN))
|
if (!(opt->flag & (MM_F_SPLICE|MM_F_SR|MM_F_NO_LJOIN))) // long join not working well without primary chains
|
||||||
mm_join_long(km, opt, qlen, n_regs, regs, a);
|
mm_join_long(km, opt, qlen, n_regs, regs, a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *km, int qlen, const char *seq, const char *qual, int *n_regs, mm_reg1_t *regs, mm128_t *a)
|
static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *km, int qlen, const char *seq, int *n_regs, mm_reg1_t *regs, mm128_t *a)
|
||||||
{
|
{
|
||||||
if (!(opt->flag & MM_F_CIGAR)) return regs;
|
if (!(opt->flag & MM_F_CIGAR)) return regs;
|
||||||
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_AVA)) {
|
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
|
||||||
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
|
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
|
||||||
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, n_regs, regs);
|
||||||
mm_set_sam_pri(*n_regs, regs);
|
mm_set_sam_pri(*n_regs, regs);
|
||||||
@@ -270,7 +258,7 @@ static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *k
|
|||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, const char **quals, int *n_regs, mm_reg1_t **regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
|
void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, int *n_regs, mm_reg1_t **regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
|
||||||
{
|
{
|
||||||
int i, j, rep_len, qlen_sum, n_regs0, n_mini_pos;
|
int i, j, rep_len, qlen_sum, n_regs0, n_mini_pos;
|
||||||
int max_chain_gap_qry, max_chain_gap_ref, is_splice = !!(opt->flag & MM_F_SPLICE), is_sr = !!(opt->flag & MM_F_SR);
|
int max_chain_gap_qry, max_chain_gap_ref, is_splice = !!(opt->flag & MM_F_SPLICE), is_sr = !!(opt->flag & MM_F_SR);
|
||||||
@@ -292,8 +280,8 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
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);
|
||||||
a = collect_seed_hits(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);
|
||||||
radix_sort_128x(a, a + n_a);
|
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);
|
||||||
|
|
||||||
if (mm_dbg_flag & MM_DBG_PRINT_SEED) {
|
if (mm_dbg_flag & MM_DBG_PRINT_SEED) {
|
||||||
fprintf(stderr, "RS\t%d\n", rep_len);
|
fprintf(stderr, "RS\t%d\n", rep_len);
|
||||||
@@ -333,8 +321,8 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
kfree(b->km, a);
|
kfree(b->km, a);
|
||||||
kfree(b->km, u);
|
kfree(b->km, u);
|
||||||
kfree(b->km, mini_pos);
|
kfree(b->km, mini_pos);
|
||||||
a = collect_seed_hits(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);
|
||||||
radix_sort_128x(a, a + n_a);
|
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 = mm_chain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->min_cnt, opt->min_chain_score, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
|
a = mm_chain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->min_cnt, opt->min_chain_score, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,7 +339,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
if (!is_sr) mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos);
|
if (!is_sr) mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos);
|
||||||
|
|
||||||
if (n_segs == 1) { // uni-segment
|
if (n_segs == 1) { // uni-segment
|
||||||
regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], quals? quals[0] : 0, &n_regs0, regs0, a);
|
regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], &n_regs0, regs0, a);
|
||||||
mm_set_mapq(n_regs0, regs0, opt->min_chain_score, opt->a, rep_len, is_sr);
|
mm_set_mapq(n_regs0, regs0, opt->min_chain_score, opt->a, rep_len, is_sr);
|
||||||
n_regs[0] = n_regs0, regs[0] = regs0;
|
n_regs[0] = n_regs0, regs[0] = regs0;
|
||||||
} else { // multi-segment
|
} else { // multi-segment
|
||||||
@@ -360,7 +348,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
free(regs0);
|
free(regs0);
|
||||||
for (i = 0; i < n_segs; ++i) {
|
for (i = 0; i < n_segs; ++i) {
|
||||||
mm_set_parent(b->km, opt->mask_level, n_regs[i], regs[i], opt->a * 2 + opt->b); // update mm_reg1_t::parent
|
mm_set_parent(b->km, opt->mask_level, n_regs[i], regs[i], opt->a * 2 + opt->b); // update mm_reg1_t::parent
|
||||||
regs[i] = align_regs(opt, mi, b->km, qlens[i], seqs[i], quals? quals[i] : 0, &n_regs[i], regs[i], seg[i].a);
|
regs[i] = align_regs(opt, mi, b->km, qlens[i], seqs[i], &n_regs[i], regs[i], seg[i].a);
|
||||||
mm_set_mapq(n_regs[i], regs[i], opt->min_chain_score, opt->a, rep_len, is_sr);
|
mm_set_mapq(n_regs[i], regs[i], opt->min_chain_score, opt->a, rep_len, is_sr);
|
||||||
}
|
}
|
||||||
mm_seg_free(b->km, n_segs, seg);
|
mm_seg_free(b->km, n_segs, seg);
|
||||||
@@ -388,7 +376,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
|
mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
|
||||||
{
|
{
|
||||||
mm_reg1_t *regs;
|
mm_reg1_t *regs;
|
||||||
mm_map_frag(mi, 1, &qlen, &seq, 0, n_regs, ®s, b, opt, qname);
|
mm_map_frag(mi, 1, &qlen, &seq, n_regs, ®s, b, opt, qname);
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,11 +404,10 @@ typedef struct {
|
|||||||
static void worker_for(void *_data, long i, int tid) // kt_for() callback
|
static void worker_for(void *_data, long i, int tid) // kt_for() callback
|
||||||
{
|
{
|
||||||
step_t *s = (step_t*)_data;
|
step_t *s = (step_t*)_data;
|
||||||
int qlens[MM_MAX_SEG], j, off = s->seg_off[i], pe_ori = s->p->opt->pe_ori, is_sr = !!(s->p->opt->flag & MM_F_SR);
|
int qlens[MM_MAX_SEG], j, off = s->seg_off[i], pe_ori = s->p->opt->pe_ori;
|
||||||
const char *qseqs[MM_MAX_SEG], *quals[MM_MAX_SEG];
|
const char *qseqs[MM_MAX_SEG];
|
||||||
mm_tbuf_t *b = s->buf[tid];
|
mm_tbuf_t *b = s->buf[tid];
|
||||||
assert(s->n_seg[i] <= MM_MAX_SEG);
|
assert(s->n_seg[i] <= MM_MAX_SEG);
|
||||||
memset(quals, 0, sizeof(char*) * MM_MAX_SEG);
|
|
||||||
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
||||||
fprintf(stderr, "QR\t%s\t%d\t%d\n", s->seq[off].name, tid, s->seq[off].l_seq);
|
fprintf(stderr, "QR\t%s\t%d\t%d\n", s->seq[off].name, tid, s->seq[off].l_seq);
|
||||||
for (j = 0; j < s->n_seg[i]; ++j) {
|
for (j = 0; j < s->n_seg[i]; ++j) {
|
||||||
@@ -428,13 +415,12 @@ static void worker_for(void *_data, long i, int tid) // kt_for() callback
|
|||||||
mm_revcomp_bseq(&s->seq[off + j]);
|
mm_revcomp_bseq(&s->seq[off + j]);
|
||||||
qlens[j] = s->seq[off + j].l_seq;
|
qlens[j] = s->seq[off + j].l_seq;
|
||||||
qseqs[j] = s->seq[off + j].seq;
|
qseqs[j] = s->seq[off + j].seq;
|
||||||
quals[j] = is_sr? s->seq[off + j].qual : 0;
|
|
||||||
}
|
}
|
||||||
if (s->p->opt->flag & MM_F_INDEPEND_SEG) {
|
if (s->p->opt->flag & MM_F_INDEPEND_SEG) {
|
||||||
for (j = 0; j < s->n_seg[i]; ++j)
|
for (j = 0; j < s->n_seg[i]; ++j)
|
||||||
mm_map_frag(s->p->mi, 1, &qlens[j], &qseqs[j], &quals[j], &s->n_reg[off+j], &s->reg[off+j], b, s->p->opt, s->seq[off+j].name);
|
mm_map_frag(s->p->mi, 1, &qlens[j], &qseqs[j], &s->n_reg[off+j], &s->reg[off+j], b, s->p->opt, s->seq[off+j].name);
|
||||||
} else {
|
} else {
|
||||||
mm_map_frag(s->p->mi, s->n_seg[i], qlens, qseqs, quals, &s->n_reg[off], &s->reg[off], b, s->p->opt, s->seq[off].name);
|
mm_map_frag(s->p->mi, s->n_seg[i], qlens, qseqs, &s->n_reg[off], &s->reg[off], b, s->p->opt, s->seq[off].name);
|
||||||
}
|
}
|
||||||
for (j = 0; j < s->n_seg[i]; ++j) // flip the query strand and coordinate to the original read strand
|
for (j = 0; j < s->n_seg[i]; ++j) // flip the query strand and coordinate to the original read strand
|
||||||
if (s->n_seg[i] == 2 && ((j == 0 && (pe_ori>>1&1)) || (j == 1 && (pe_ori&1)))) {
|
if (s->n_seg[i] == 2 && ((j == 0 && (pe_ori>>1&1)) || (j == 1 && (pe_ori&1)))) {
|
||||||
|
|||||||
@@ -5,26 +5,30 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define MM_F_NO_SELF 0x001
|
#define MM_F_NO_DIAG 0x001 // no exact diagonal hit
|
||||||
#define MM_F_AVA 0x002
|
#define MM_F_NO_DUAL 0x002 // skip pairs where query name is lexicographically larger than target name
|
||||||
#define MM_F_CIGAR 0x004
|
#define MM_F_CIGAR 0x004
|
||||||
#define MM_F_OUT_SAM 0x008
|
#define MM_F_OUT_SAM 0x008
|
||||||
#define MM_F_NO_QUAL 0x010
|
#define MM_F_NO_QUAL 0x010
|
||||||
#define MM_F_OUT_CG 0x020
|
#define MM_F_OUT_CG 0x020
|
||||||
#define MM_F_OUT_CS 0x040
|
#define MM_F_OUT_CS 0x040
|
||||||
#define MM_F_SPLICE 0x080 // splice mode
|
#define MM_F_SPLICE 0x080 // splice mode
|
||||||
#define MM_F_SPLICE_FOR 0x100 // match GT-AG
|
#define MM_F_SPLICE_FOR 0x100 // match GT-AG
|
||||||
#define MM_F_SPLICE_REV 0x200 // match CT-AC, the reverse complement of GT-AG
|
#define MM_F_SPLICE_REV 0x200 // match CT-AC, the reverse complement of GT-AG
|
||||||
#define MM_F_NO_LJOIN 0x400
|
#define MM_F_NO_LJOIN 0x400
|
||||||
#define MM_F_OUT_CS_LONG 0x800
|
#define MM_F_OUT_CS_LONG 0x800
|
||||||
#define MM_F_SR 0x1000
|
#define MM_F_SR 0x1000
|
||||||
#define MM_F_FRAG_MODE 0x2000
|
#define MM_F_FRAG_MODE 0x2000
|
||||||
#define MM_F_NO_PRINT_2ND 0x4000
|
#define MM_F_NO_PRINT_2ND 0x4000
|
||||||
#define MM_F_2_IO_THREADS 0x8000
|
#define MM_F_2_IO_THREADS 0x8000
|
||||||
#define MM_F_LONG_CIGAR 0x10000
|
#define MM_F_LONG_CIGAR 0x10000
|
||||||
#define MM_F_INDEPEND_SEG 0x20000
|
#define MM_F_INDEPEND_SEG 0x20000
|
||||||
#define MM_F_SPLICE_FLANK 0x40000
|
#define MM_F_SPLICE_FLANK 0x40000
|
||||||
#define MM_F_SOFTCLIP 0x80000
|
#define MM_F_SOFTCLIP 0x80000
|
||||||
|
#define MM_F_FOR_ONLY 0x100000
|
||||||
|
#define MM_F_REV_ONLY 0x200000
|
||||||
|
#define MM_F_HEAP_SORT 0x400000
|
||||||
|
#define MM_F_ALL_CHAINS 0x800000
|
||||||
|
|
||||||
#define MM_I_HPC 0x1
|
#define MM_I_HPC 0x1
|
||||||
#define MM_I_NO_SEQ 0x2
|
#define MM_I_NO_SEQ 0x2
|
||||||
@@ -78,7 +82,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, dummy:16;
|
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, dummy:8;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
float div;
|
float div;
|
||||||
mm_extra_t *p;
|
mm_extra_t *p;
|
||||||
@@ -155,6 +159,7 @@ extern double mm_realtime0; // wall-clock timer
|
|||||||
* @return 0 if success; -1 if _present_ unknown
|
* @return 0 if success; -1 if _present_ unknown
|
||||||
*/
|
*/
|
||||||
int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo);
|
int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo);
|
||||||
|
int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update mm_mapopt_t::mid_occ via mm_mapopt_t::mid_occ_frac
|
* Update mm_mapopt_t::mid_occ via mm_mapopt_t::mid_occ_frac
|
||||||
@@ -207,6 +212,21 @@ void mm_idx_reader_close(mm_idx_reader_t *r);
|
|||||||
|
|
||||||
int mm_idx_reader_eof(const mm_idx_reader_t *r);
|
int mm_idx_reader_eof(const mm_idx_reader_t *r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an index from strings in memory
|
||||||
|
*
|
||||||
|
* @param w minimizer window size
|
||||||
|
* @param k minimizer k-mer size
|
||||||
|
* @param is_hpc use HPC k-mer if true
|
||||||
|
* @param bucket_bits number of bits for the first level of the hash table
|
||||||
|
* @param n number of sequences
|
||||||
|
* @param seq sequences in A/C/G/T
|
||||||
|
* @param name sequence names; could be NULL
|
||||||
|
*
|
||||||
|
* @return minimap2 index
|
||||||
|
*/
|
||||||
|
mm_idx_t *mm_idx_str(int w, int k, int is_hpc, int bucket_bits, int n, const char **seq, const char **name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print index statistics to stderr
|
* Print index statistics to stderr
|
||||||
*
|
*
|
||||||
@@ -260,6 +280,8 @@ void mm_tbuf_destroy(mm_tbuf_t *b);
|
|||||||
*/
|
*/
|
||||||
mm_reg1_t *mm_map(const mm_idx_t *mi, int l_seq, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *name);
|
mm_reg1_t *mm_map(const mm_idx_t *mi, int l_seq, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *name);
|
||||||
|
|
||||||
|
void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, int *n_regs, mm_reg1_t **regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Align a fasta/fastq file and print alignments to stdout
|
* Align a fasta/fastq file and print alignments to stdout
|
||||||
*
|
*
|
||||||
|
|||||||
+54
-18
@@ -1,4 +1,4 @@
|
|||||||
.TH minimap2 1 "12 December 2017" "minimap2-2.6 (r623)" "Bioinformatics tools"
|
.TH minimap2 1 "1 February 2018" "minimap2-2.8 (r672)" "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
|
||||||
@@ -129,7 +129,7 @@ Ignore top
|
|||||||
fraction of most frequent minimizers [0.0002]
|
fraction of most frequent minimizers [0.0002]
|
||||||
.TP
|
.TP
|
||||||
.BI -g \ INT
|
.BI -g \ INT
|
||||||
Stop chain enlongation if there are no minimizers in
|
Stop chain enlongation if there are no minimizers within
|
||||||
.IR INT -bp
|
.IR INT -bp
|
||||||
[10000].
|
[10000].
|
||||||
.TP
|
.TP
|
||||||
@@ -148,11 +148,28 @@ Discard chains with chaining score
|
|||||||
[40]. Chaining score equals the approximate number of matching bases minus a
|
[40]. Chaining score equals the approximate number of matching bases minus a
|
||||||
concave gap penalty. It is computed with dynamic programming.
|
concave gap penalty. It is computed with dynamic programming.
|
||||||
.TP
|
.TP
|
||||||
|
.B -D
|
||||||
|
If query sequence name/length are identical to the target name/length, ignore
|
||||||
|
diagonal anchors. This option also reduces DP-based extension along the
|
||||||
|
diagonal.
|
||||||
|
.TP
|
||||||
|
.B -P
|
||||||
|
Retain all chains and don't attempt to set primary chains. Options
|
||||||
|
.B -p
|
||||||
|
and
|
||||||
|
.B -N
|
||||||
|
have no effect when this option is in use.
|
||||||
|
.TP
|
||||||
|
.BR --dual = yes | no
|
||||||
|
During chaining, whether to skip pairs wherein the query name is
|
||||||
|
lexicographically greater than the target name [yes]
|
||||||
|
.TP
|
||||||
.B -X
|
.B -X
|
||||||
Perform all-vs-all mapping. In this mode, if the query sequence name is
|
Equivalent to
|
||||||
lexicographically larger than the target sequence name, the hits between them
|
.RB ' -DP
|
||||||
will be suppressed; if the query sequence name is the same as the target name,
|
.BR --dual = no
|
||||||
diagonal minimizer hits will also be suppressed.
|
.BR --no-long-join '.
|
||||||
|
Primarily used for all-vs-all read overlapping.
|
||||||
.TP
|
.TP
|
||||||
.BI -p \ FLOAT
|
.BI -p \ FLOAT
|
||||||
Minimal secondary-to-primary score ratio to output secondary mappings [0.8].
|
Minimal secondary-to-primary score ratio to output secondary mappings [0.8].
|
||||||
@@ -162,6 +179,9 @@ the chain with a lower score is secondary to the chain with a higher score.
|
|||||||
If the ratio of the scores is below
|
If the ratio of the scores is below
|
||||||
.IR FLOAT ,
|
.IR FLOAT ,
|
||||||
the secondary chain will not be outputted or extended with DP alignment later.
|
the secondary chain will not be outputted or extended with DP alignment later.
|
||||||
|
This option has no effect when
|
||||||
|
.B -X
|
||||||
|
is applied.
|
||||||
.TP
|
.TP
|
||||||
.BI -N \ INT
|
.BI -N \ INT
|
||||||
Output at most
|
Output at most
|
||||||
@@ -179,9 +199,14 @@ Increasing this option slows down spliced alignment. [200k]
|
|||||||
.TP
|
.TP
|
||||||
.BI -F \ NUM
|
.BI -F \ NUM
|
||||||
Maximum fragment length (aka insert size; effective with
|
Maximum fragment length (aka insert size; effective with
|
||||||
.BR -xsr / --frag)
|
.BR -xsr / --frag = yes )
|
||||||
[800]
|
[800]
|
||||||
.TP
|
.TP
|
||||||
|
.BI -M \ FLOAT
|
||||||
|
Mark as secondary a chain that overlaps with a better chain by
|
||||||
|
.I FLOAT
|
||||||
|
or more of the shorter chain [0.5]
|
||||||
|
.TP
|
||||||
.BI --max-chain-skip \ INT
|
.BI --max-chain-skip \ INT
|
||||||
A heuristics that stops chaining early [50]. Minimap2 uses dynamic programming
|
A heuristics that stops chaining early [50]. Minimap2 uses dynamic programming
|
||||||
for chaining. The time complexity is quadratic in the number of seeds. This
|
for chaining. The time complexity is quadratic in the number of seeds. This
|
||||||
@@ -204,8 +229,20 @@ applies a second round of chaining with a higher minimizer occurrence threshold
|
|||||||
if no good chain is found. In addition, minimap2 attempts to patch gaps between
|
if no good chain is found. In addition, minimap2 attempts to patch gaps between
|
||||||
seeds with ungapped alignment.
|
seeds with ungapped alignment.
|
||||||
.TP
|
.TP
|
||||||
.BR --frag [= no | yes ]
|
.BR --frag = no | yes
|
||||||
Whether to enable the fragment mode [no]
|
Whether to enable the fragment mode [no]
|
||||||
|
.TP
|
||||||
|
.B --for-only
|
||||||
|
Only map to the forward strand of the reference sequences. For paired-end
|
||||||
|
reads in the forward-reverse orientation, the first read is mapped to forward
|
||||||
|
strand of the reference and the second read to the reverse stand.
|
||||||
|
.TP
|
||||||
|
.B --rev-only
|
||||||
|
Only map to the reverse complement strand of the reference sequences.
|
||||||
|
.TP
|
||||||
|
.BR --heap-sort = no | yes
|
||||||
|
If yes, sort anchors with heap merge, instead of radix sort. Heap merge is
|
||||||
|
faster for short reads, but slower for long reads. [no]
|
||||||
.SS Alignment options
|
.SS Alignment options
|
||||||
.TP 10
|
.TP 10
|
||||||
.BI -A \ INT
|
.BI -A \ INT
|
||||||
@@ -255,14 +292,13 @@ no attempt to match GT-AG [n]
|
|||||||
.BI --end-bonus \ INT
|
.BI --end-bonus \ INT
|
||||||
Score bonus when alignment extends to the end of the query sequence [0].
|
Score bonus when alignment extends to the end of the query sequence [0].
|
||||||
.TP
|
.TP
|
||||||
.BR --splice-flank [= yes | no ]
|
.BR --splice-flank = yes | no
|
||||||
Assume the next base to a
|
Assume the next base to a
|
||||||
.B GT
|
.B GT
|
||||||
donor site tends to be A/G (91% in human and 92% in mouse) and the preceding
|
donor site tends to be A/G (91% in human and 92% in mouse) and the preceding
|
||||||
base to a
|
base to a
|
||||||
.B AG
|
.B AG
|
||||||
acceptor tends to be C/T [yes with
|
acceptor tends to be C/T [no].
|
||||||
.BR --splice ].
|
|
||||||
This trend is evolutionarily conservative, all the way to S. cerevisiae
|
This trend is evolutionarily conservative, all the way to S. cerevisiae
|
||||||
(PMID:18688272). Specifying this option generally leads to higher junction
|
(PMID:18688272). Specifying this option generally leads to higher junction
|
||||||
accuracy by several percents, so it is applied by default with
|
accuracy by several percents, so it is applied by default with
|
||||||
@@ -352,7 +388,7 @@ K/M/G/k/m/g suffix is accepted. A large
|
|||||||
helps load balancing in the multi-threading mode, at the cost of increased
|
helps load balancing in the multi-threading mode, at the cost of increased
|
||||||
memory.
|
memory.
|
||||||
.TP
|
.TP
|
||||||
.BR --secondary [= yes | no ]
|
.BR --secondary = yes | no
|
||||||
Whether to output secondary alignments [yes]
|
Whether to output secondary alignments [yes]
|
||||||
.TP
|
.TP
|
||||||
.B --version
|
.B --version
|
||||||
@@ -399,13 +435,13 @@ Up to 10% sequence divergence.
|
|||||||
.B ava-pb
|
.B ava-pb
|
||||||
PacBio all-vs-all overlap mapping
|
PacBio all-vs-all overlap mapping
|
||||||
.RB ( -Hk19
|
.RB ( -Hk19
|
||||||
.B -w5 -Xp0 -m100 -g10000 --max-chain-skip
|
.B -Xw5 -m100 -g10000 --max-chain-skip
|
||||||
.BR 25 ).
|
.BR 25 ).
|
||||||
.TP
|
.TP
|
||||||
.B ava-ont
|
.B ava-ont
|
||||||
Oxford Nanopore all-vs-all overlap mapping
|
Oxford Nanopore all-vs-all overlap mapping
|
||||||
.RB ( -k15
|
.RB ( -k15
|
||||||
.B -w5 -Xp0 -m100 -g10000 --max-chain-skip
|
.B -Xw5 -m100 -g10000 --max-chain-skip
|
||||||
.BR 25 ).
|
.BR 25 ).
|
||||||
Similarly, the major difference from
|
Similarly, the major difference from
|
||||||
.B ava-pb
|
.B ava-pb
|
||||||
@@ -427,8 +463,8 @@ tag ignores introns to demote hits to pseudogenes.
|
|||||||
.B sr
|
.B sr
|
||||||
Short single-end reads without splicing
|
Short single-end reads without splicing
|
||||||
.RB ( -k21
|
.RB ( -k21
|
||||||
.B -w11 --sr --frag -A2 -B8 -O12,32 -E2,1 -r50 -p.5 -N20 -f1000,5000 -n2 -m20
|
.B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -r50 -p.5 -N20 -f1000,5000 -n2 -m20
|
||||||
.B -s40 -g200 -2K50m
|
.B -s40 -g200 -2K50m --heap-sort=yes
|
||||||
.BR --secondary=no ).
|
.BR --secondary=no ).
|
||||||
.RE
|
.RE
|
||||||
.SS Miscellaneous options
|
.SS Miscellaneous options
|
||||||
@@ -522,8 +558,8 @@ where seed positions may be suboptimal. This should not be a big concern
|
|||||||
because even the optimal alignment may be wrong in such regions.
|
because even the optimal alignment may be wrong in such regions.
|
||||||
.TP
|
.TP
|
||||||
*
|
*
|
||||||
Minimap2 requires SSE2 instructions to compile. It is possible to add
|
Minimap2 requires SSE2 or NEON instructions to compile. It is possible to add
|
||||||
non-SSE2 support, but it would make minimap2 slower by several times.
|
non-SSE2/NEON support, but it would make minimap2 slower by several times.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.PP
|
.PP
|
||||||
miniasm(1), minimap(1), bwa(1).
|
miniasm(1), minimap(1), bwa(1).
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "minimap.h"
|
#include "mmpriv.h"
|
||||||
|
|
||||||
int mm_verbose = 1;
|
int mm_verbose = 1;
|
||||||
int mm_dbg_flag = 0;
|
int mm_dbg_flag = 0;
|
||||||
|
|||||||
@@ -0,0 +1,258 @@
|
|||||||
|
/*******************************
|
||||||
|
* Command line option parsing *
|
||||||
|
*******************************/
|
||||||
|
|
||||||
|
var getopt = function(args, ostr) {
|
||||||
|
var oli; // option letter list index
|
||||||
|
if (typeof(getopt.place) == 'undefined')
|
||||||
|
getopt.ind = 0, getopt.arg = null, getopt.place = -1;
|
||||||
|
if (getopt.place == -1) { // update scanning pointer
|
||||||
|
if (getopt.ind >= args.length || args[getopt.ind].charAt(getopt.place = 0) != '-') {
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (getopt.place + 1 < args[getopt.ind].length && args[getopt.ind].charAt(++getopt.place) == '-') { // found "--"
|
||||||
|
++getopt.ind;
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var optopt = args[getopt.ind].charAt(getopt.place++); // character checked for validity
|
||||||
|
if (optopt == ':' || (oli = ostr.indexOf(optopt)) < 0) {
|
||||||
|
if (optopt == '-') return null; // if the user didn't specify '-' as an option, assume it means null.
|
||||||
|
if (getopt.place < 0) ++getopt.ind;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
if (oli+1 >= ostr.length || ostr.charAt(++oli) != ':') { // don't need argument
|
||||||
|
getopt.arg = null;
|
||||||
|
if (getopt.place < 0 || getopt.place >= args[getopt.ind].length) ++getopt.ind, getopt.place = -1;
|
||||||
|
} else { // need an argument
|
||||||
|
if (getopt.place >= 0 && getopt.place < args[getopt.ind].length)
|
||||||
|
getopt.arg = args[getopt.ind].substr(getopt.place);
|
||||||
|
else if (args.length <= ++getopt.ind) { // no arg
|
||||||
|
getopt.place = -1;
|
||||||
|
if (ostr.length > 0 && ostr.charAt(0) == ':') return ':';
|
||||||
|
return '?';
|
||||||
|
} else getopt.arg = args[getopt.ind]; // white space
|
||||||
|
getopt.place = -1;
|
||||||
|
++getopt.ind;
|
||||||
|
}
|
||||||
|
return optopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************
|
||||||
|
* Interval operations *
|
||||||
|
***********************/
|
||||||
|
|
||||||
|
Interval = {};
|
||||||
|
|
||||||
|
Interval.sort = function(a)
|
||||||
|
{
|
||||||
|
if (typeof a[0] == 'number')
|
||||||
|
a.sort(function(x, y) { return x - y });
|
||||||
|
else a.sort(function(x, y) { return x[0] != y[0]? x[0] - y[0] : x[1] - y[1] });
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval.merge = function(a, sorted)
|
||||||
|
{
|
||||||
|
if (typeof sorted == 'undefined') sorted = true;
|
||||||
|
if (!sorted) Interval.sort(a);
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 1; i < a.length; ++i) {
|
||||||
|
if (a[k][1] >= a[i][0])
|
||||||
|
a[k][1] = a[k][1] > a[i][1]? a[k][1] : a[i][1];
|
||||||
|
else a[++k] = a[i].slice(0);
|
||||||
|
}
|
||||||
|
a.length = k + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval.dedup = function(a, sorted)
|
||||||
|
{
|
||||||
|
if (typeof sorted == 'undefined') sorted = true;
|
||||||
|
if (!sorted) Interval.sort(a);
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 1; i < a.length; ++i)
|
||||||
|
if (a[k][0] != a[i][0] || a[k][1] != a[i][1])
|
||||||
|
a[++k] = a[i].slice(0);
|
||||||
|
a.length = k + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval.index_end = function(a, sorted)
|
||||||
|
{
|
||||||
|
if (a.length == 0) return;
|
||||||
|
if (typeof sorted == 'undefined') sorted = true;
|
||||||
|
if (!sorted) Interval.sort(a);
|
||||||
|
a[0].push(0);
|
||||||
|
var k = 0, k_en = a[0][1];
|
||||||
|
for (var i = 1; i < a.length; ++i) {
|
||||||
|
if (k_en <= a[i][0]) {
|
||||||
|
for (++k; k < i; ++k)
|
||||||
|
if (a[k][1] > a[i][0])
|
||||||
|
break;
|
||||||
|
k_en = a[k][1];
|
||||||
|
}
|
||||||
|
a[i].push(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval.find_intv = function(a, x)
|
||||||
|
{
|
||||||
|
var left = -1, right = a.length;
|
||||||
|
if (typeof a[0] == 'number') {
|
||||||
|
while (right - left > 1) {
|
||||||
|
var mid = left + ((right - left) >> 1);
|
||||||
|
if (a[mid] > x) right = mid;
|
||||||
|
else if (a[mid] < x) left = mid;
|
||||||
|
else return mid;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (right - left > 1) {
|
||||||
|
var mid = left + ((right - left) >> 1);
|
||||||
|
if (a[mid][0] > x) right = mid;
|
||||||
|
else if (a[mid][0] < x) left = mid;
|
||||||
|
else return mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
|
Interval.find_ovlp = function(a, st, en)
|
||||||
|
{
|
||||||
|
if (a.length == 0 || st >= en) return [];
|
||||||
|
var l = Interval.find_intv(a, st);
|
||||||
|
var k = l < 0? 0 : a[l][a[l].length - 1];
|
||||||
|
var b = [];
|
||||||
|
for (var i = k; i < a.length; ++i) {
|
||||||
|
if (a[i][0] >= en) break;
|
||||||
|
else if (st < a[i][1])
|
||||||
|
b.push(a[i]);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************
|
||||||
|
* Main function *
|
||||||
|
*****************/
|
||||||
|
|
||||||
|
function read_bed(fn, to_merge, to_dedup)
|
||||||
|
{
|
||||||
|
var file = new File(fn);
|
||||||
|
var buf = new Bytes();
|
||||||
|
var h = {};
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
if (h[t[0]] == null)
|
||||||
|
h[t[0]] = [];
|
||||||
|
var bst = parseInt(t[1]);
|
||||||
|
var ben = parseInt(t[2]);
|
||||||
|
if (t.length >= 12 && /^\d+$/.test(t[9])) {
|
||||||
|
t[9] = parseInt(t[9]);
|
||||||
|
var sz = t[10].split(",");
|
||||||
|
var st = t[11].split(",");
|
||||||
|
for (var i = 0; i < t[9]; ++i) {
|
||||||
|
st[i] = parseInt(st[i]);
|
||||||
|
sz[i] = parseInt(sz[i]);
|
||||||
|
h[t[0]].push([bst + st[i], bst + st[i] + sz[i], 0, 0, 0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
h[t[0]].push([bst, ben, 0, 0, 0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.destroy();
|
||||||
|
file.close();
|
||||||
|
for (var chr in h) {
|
||||||
|
if (to_merge) Interval.merge(h[chr], false);
|
||||||
|
else if (to_dedup) Interval.dedup(h[chr], false);
|
||||||
|
else Interval.sort(h[chr]);
|
||||||
|
Interval.index_end(h[chr]);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(args)
|
||||||
|
{
|
||||||
|
var c, print_len = false, to_merge = true, to_dedup = false, fn_excl = null;
|
||||||
|
while ((c = getopt(args, "pde:")) != null) {
|
||||||
|
if (c == 'p') print_len = true;
|
||||||
|
else if (c == 'd') to_dedup = true, to_merge = false;
|
||||||
|
else if (c == 'e') fn_excl = getopt.arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length - getopt.ind < 2) {
|
||||||
|
print("Usage: k8 cnt-feat.js [options] <target.bed> <feature.bed>");
|
||||||
|
print("Options:");
|
||||||
|
print(" -e FILE exclude features overlapping regions in BED FILE []");
|
||||||
|
print(" -p print number of covered bases for each feature");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var excl = fn_excl != null? read_bed(fn_excl, true, false) : null;
|
||||||
|
var target = read_bed(args[getopt.ind], to_merge, to_dedup);
|
||||||
|
|
||||||
|
var file, buf = new Bytes();
|
||||||
|
var tot_len = 0, hit_len = 0;
|
||||||
|
file = args[getopt.ind+1] != '-'? new File(args[getopt.ind+1]) : new File();
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
var a = [];
|
||||||
|
var bst = parseInt(t[1]);
|
||||||
|
var ben = parseInt(t[2]);
|
||||||
|
if (t.length >= 12 && /^\d+$/.test(t[9])) { // BED12
|
||||||
|
t[9] = parseInt(t[9]);
|
||||||
|
var sz = t[10].split(",");
|
||||||
|
var st = t[11].split(",");
|
||||||
|
for (var i = 0; i < t[9]; ++i) {
|
||||||
|
st[i] = parseInt(st[i]);
|
||||||
|
sz[i] = parseInt(sz[i]);
|
||||||
|
a.push([bst + st[i], bst + st[i] + sz[i], false]);
|
||||||
|
}
|
||||||
|
} else a.push([bst, ben, false]); // 3-column BED
|
||||||
|
var feat_len = 0;
|
||||||
|
for (var i = 0; i < a.length; ++i) {
|
||||||
|
if (excl != null && excl[t[0]] != null) {
|
||||||
|
var oe = Interval.find_ovlp(excl[t[0]], a[i][0], a[i][1]);
|
||||||
|
if (oe.length > 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
a[i][2] = true;
|
||||||
|
feat_len += a[i][1] - a[i][0];
|
||||||
|
}
|
||||||
|
tot_len += feat_len;
|
||||||
|
if (target[t[0]] == null) continue;
|
||||||
|
var b = [];
|
||||||
|
for (var i = 0; i < a.length; ++i) {
|
||||||
|
if (!a[i][2]) continue;
|
||||||
|
var o = Interval.find_ovlp(target[t[0]], a[i][0], a[i][1]);
|
||||||
|
for (var j = 0; j < o.length; ++j) {
|
||||||
|
var max_st = o[j][0] > a[i][0]? o[j][0] : a[i][0];
|
||||||
|
var min_en = o[j][1] < a[i][1]? o[j][1] : a[i][1];
|
||||||
|
b.push([max_st, min_en]);
|
||||||
|
o[j][2] += min_en - max_st;
|
||||||
|
++o[j][3];
|
||||||
|
if (max_st == o[j][0] && min_en == o[j][1])
|
||||||
|
++o[j][4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// find the length covered
|
||||||
|
var feat_hit_len = 0;
|
||||||
|
if (b.length > 0) {
|
||||||
|
b.sort(function(a,b) {return a[0]-b[0]});
|
||||||
|
var st = b[0][0], en = b[0][1];
|
||||||
|
for (var i = 1; i < b.length; ++i) {
|
||||||
|
if (b[i][0] <= en) en = en > b[i][1]? en : b[i][1];
|
||||||
|
else feat_hit_len += en - st, st = b[i][0], en = b[i][1];
|
||||||
|
}
|
||||||
|
feat_hit_len += en - st;
|
||||||
|
}
|
||||||
|
hit_len += feat_hit_len;
|
||||||
|
if (print_len) print('F', t.slice(0, 4).join("\t"), feat_len, feat_hit_len);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
buf.destroy();
|
||||||
|
|
||||||
|
warn("# feature bases: " + tot_len);
|
||||||
|
warn("# feature bases overlapping targets: " + hit_len + ' (' + (100.0 * hit_len / tot_len).toFixed(2) + '%)');
|
||||||
|
}
|
||||||
|
|
||||||
|
main(arguments);
|
||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
var getopt = function(args, ostr) {
|
||||||
|
var oli; // option letter list index
|
||||||
|
if (typeof(getopt.place) == 'undefined')
|
||||||
|
getopt.ind = 0, getopt.arg = null, getopt.place = -1;
|
||||||
|
if (getopt.place == -1) { // update scanning pointer
|
||||||
|
if (getopt.ind >= args.length || args[getopt.ind].charAt(getopt.place = 0) != '-') {
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (getopt.place + 1 < args[getopt.ind].length && args[getopt.ind].charAt(++getopt.place) == '-') { // found "--"
|
||||||
|
++getopt.ind;
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var optopt = args[getopt.ind].charAt(getopt.place++); // character checked for validity
|
||||||
|
if (optopt == ':' || (oli = ostr.indexOf(optopt)) < 0) {
|
||||||
|
if (optopt == '-') return null; // if the user didn't specify '-' as an option, assume it means null.
|
||||||
|
if (getopt.place < 0) ++getopt.ind;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
if (oli+1 >= ostr.length || ostr.charAt(++oli) != ':') { // don't need argument
|
||||||
|
getopt.arg = null;
|
||||||
|
if (getopt.place < 0 || getopt.place >= args[getopt.ind].length) ++getopt.ind, getopt.place = -1;
|
||||||
|
} else { // need an argument
|
||||||
|
if (getopt.place >= 0 && getopt.place < args[getopt.ind].length)
|
||||||
|
getopt.arg = args[getopt.ind].substr(getopt.place);
|
||||||
|
else if (args.length <= ++getopt.ind) { // no arg
|
||||||
|
getopt.place = -1;
|
||||||
|
if (ostr.length > 0 && ostr.charAt(0) == ':') return ':';
|
||||||
|
return '?';
|
||||||
|
} else getopt.arg = args[getopt.ind]; // white space
|
||||||
|
getopt.place = -1;
|
||||||
|
++getopt.ind;
|
||||||
|
}
|
||||||
|
return optopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
var c, fn_ucsc_fai = null, is_short = false;
|
||||||
|
while ((c = getopt(arguments, "u:s")) != null) {
|
||||||
|
if (c == 'u') fn_ucsc_fai = getopt.arg;
|
||||||
|
else if (c == 's') is_short = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getopt.ind == arguments.length) {
|
||||||
|
print("Usage: k8 gff2bed.js [-u ucsc-genome.fa.fai] <in.gff>");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ens2ucsc = {};
|
||||||
|
if (fn_ucsc_fai != null) {
|
||||||
|
var buf = new Bytes();
|
||||||
|
var file = new File(fn_ucsc_fai);
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
var s = t[0];
|
||||||
|
if (/_(random|alt|decoy)$/.test(s)) {
|
||||||
|
s = s.replace(/_(random|alt|decoy)$/, '');
|
||||||
|
s = s.replace(/^chr\S+_/, '');
|
||||||
|
} else {
|
||||||
|
s = s.replace(/^chrUn_/, '');
|
||||||
|
}
|
||||||
|
s = s.replace(/v(\d+)/, ".$1");
|
||||||
|
if (s != t[0]) ens2ucsc[s] = t[0];
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
buf.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
var colors = {
|
||||||
|
'protein_coding':'0,128,255',
|
||||||
|
'lincRNA':'0,192,0',
|
||||||
|
'snRNA':'0,192,0',
|
||||||
|
'miRNA':'0,192,0',
|
||||||
|
'misc_RNA':'0,192,0'
|
||||||
|
};
|
||||||
|
|
||||||
|
function print_bed12(exons, cds_st, cds_en, is_short)
|
||||||
|
{
|
||||||
|
if (exons.length == 0) return;
|
||||||
|
var name = is_short? exons[0][7] + "|" + exons[0][5] : exons[0].slice(4, 7).join("|");
|
||||||
|
var a = exons.sort(function(a,b) {return a[1]-b[1]});
|
||||||
|
var sizes = [], starts = [], st, en;
|
||||||
|
st = a[0][1];
|
||||||
|
en = a[a.length - 1][2];
|
||||||
|
if (cds_st == 1<<30) cds_st = st;
|
||||||
|
if (cds_en == 0) cds_en = en;
|
||||||
|
if (cds_st < st || cds_en > en)
|
||||||
|
throw Error("inconsistent thick start or end for transcript " + a[0][4]);
|
||||||
|
for (var i = 0; i < a.length; ++i) {
|
||||||
|
sizes.push(a[i][2] - a[i][1]);
|
||||||
|
starts.push(a[i][1] - st);
|
||||||
|
}
|
||||||
|
var color = colors[a[0][5]];
|
||||||
|
if (color == null) color = '196,196,196';
|
||||||
|
print(a[0][0], st, en, name, 1000, a[0][3], cds_st, cds_en, color, a.length, sizes.join(",") + ",", starts.join(",") + ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
var re_gtf = /(transcript_id|transcript_type|transcript_biotype|gene_name|transcript_name) "([^"]+)";/g;
|
||||||
|
var re_gff3 = /(transcript_id|transcript_type|transcript_biotype|gene_name|transcript_name)=([^;]+)/g;
|
||||||
|
var buf = new Bytes();
|
||||||
|
var file = new File(arguments[getopt.ind]);
|
||||||
|
|
||||||
|
var exons = [], cds_st = 1<<30, cds_en = 0, last_id = null;
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
if (t[0].charAt(0) == '#') continue;
|
||||||
|
if (t[2] != "CDS" && t[2] != "exon") continue;
|
||||||
|
t[3] = parseInt(t[3]) - 1;
|
||||||
|
t[4] = parseInt(t[4]);
|
||||||
|
var id = null, type = "", gname = "N/A", biotype = "", m, tname = "N/A";
|
||||||
|
while ((m = re_gtf.exec(t[8])) != null) {
|
||||||
|
if (m[1] == "transcript_id") id = m[2];
|
||||||
|
else if (m[1] == "transcript_type") type = m[2];
|
||||||
|
else if (m[1] == "transcript_biotype") biotype = m[2];
|
||||||
|
else if (m[1] == "gene_name") name = m[2];
|
||||||
|
else if (m[1] == "transcript_name") tname = m[2];
|
||||||
|
}
|
||||||
|
while ((m = re_gff3.exec(t[8])) != null) {
|
||||||
|
if (m[1] == "transcript_id") id = m[2];
|
||||||
|
else if (m[1] == "transcript_type") type = m[2];
|
||||||
|
else if (m[1] == "transcript_biotype") biotype = m[2];
|
||||||
|
else if (m[1] == "gene_name") name = m[2];
|
||||||
|
else if (m[1] == "transcript_name") tname = m[2];
|
||||||
|
}
|
||||||
|
if (type == "" && biotype != "") type = biotype;
|
||||||
|
if (id == null) throw Error("No transcript_id");
|
||||||
|
if (id != last_id) {
|
||||||
|
print_bed12(exons, cds_st, cds_en, is_short);
|
||||||
|
exons = [], cds_st = 1<<30, cds_en = 0;
|
||||||
|
last_id = id;
|
||||||
|
}
|
||||||
|
if (t[2] == "CDS") {
|
||||||
|
cds_st = cds_st < t[3]? cds_st : t[3];
|
||||||
|
cds_en = cds_en > t[4]? cds_en : t[4];
|
||||||
|
} else if (t[2] == "exon") {
|
||||||
|
if (fn_ucsc_fai != null) {
|
||||||
|
if (ens2ucsc[t[0]] != null)
|
||||||
|
t[0] = ens2ucsc[t[0]];
|
||||||
|
else if (/^[A-Z]+\d+\.\d+$/.test(t[0]))
|
||||||
|
t[0] = t[0].replace(/([A-Z]+\d+)\.(\d+)/, "chrUn_$1v$2");
|
||||||
|
}
|
||||||
|
exons.push([t[0], t[3], t[4], t[6], id, type, name, tname]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (last_id != null)
|
||||||
|
print_bed12(exons, cds_st, cds_en, is_short);
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
buf.destroy();
|
||||||
+105
@@ -0,0 +1,105 @@
|
|||||||
|
var getopt = function(args, ostr) {
|
||||||
|
var oli; // option letter list index
|
||||||
|
if (typeof(getopt.place) == 'undefined')
|
||||||
|
getopt.ind = 0, getopt.arg = null, getopt.place = -1;
|
||||||
|
if (getopt.place == -1) { // update scanning pointer
|
||||||
|
if (getopt.ind >= args.length || args[getopt.ind].charAt(getopt.place = 0) != '-') {
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (getopt.place + 1 < args[getopt.ind].length && args[getopt.ind].charAt(++getopt.place) == '-') { // found "--"
|
||||||
|
++getopt.ind;
|
||||||
|
getopt.place = -1;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var optopt = args[getopt.ind].charAt(getopt.place++); // character checked for validity
|
||||||
|
if (optopt == ':' || (oli = ostr.indexOf(optopt)) < 0) {
|
||||||
|
if (optopt == '-') return null; // if the user didn't specify '-' as an option, assume it means null.
|
||||||
|
if (getopt.place < 0) ++getopt.ind;
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
if (oli+1 >= ostr.length || ostr.charAt(++oli) != ':') { // don't need argument
|
||||||
|
getopt.arg = null;
|
||||||
|
if (getopt.place < 0 || getopt.place >= args[getopt.ind].length) ++getopt.ind, getopt.place = -1;
|
||||||
|
} else { // need an argument
|
||||||
|
if (getopt.place >= 0 && getopt.place < args[getopt.ind].length)
|
||||||
|
getopt.arg = args[getopt.ind].substr(getopt.place);
|
||||||
|
else if (args.length <= ++getopt.ind) { // no arg
|
||||||
|
getopt.place = -1;
|
||||||
|
if (ostr.length > 0 && ostr.charAt(0) == ':') return ':';
|
||||||
|
return '?';
|
||||||
|
} else getopt.arg = args[getopt.ind]; // white space
|
||||||
|
getopt.place = -1;
|
||||||
|
++getopt.ind;
|
||||||
|
}
|
||||||
|
return optopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
var c, min_ovlp = 2000, min_frac = 0.95, min_mapq = 10;
|
||||||
|
while ((c = getopt(arguments, "q:l:f:")) != null) {
|
||||||
|
if (c == 'q') min_mapq = parseInt(getopt.arg);
|
||||||
|
else if (c == 'l') min_ovlp = parseInt(getopt.arg);
|
||||||
|
else if (c == 'f') min_frac = parseFloat(getopt.arg);
|
||||||
|
}
|
||||||
|
if (arguments.length - getopt.ind < 2) {
|
||||||
|
print("Usage: sort -k6,6 -k8,8n to-ref.paf | k8 ov-eval.js [options] - <ovlp.paf>");
|
||||||
|
print("Options:");
|
||||||
|
print(" -l INT min overlap length [2000]");
|
||||||
|
print(" -q INT min mapping quality [10]");
|
||||||
|
print(" -f FLOAT min fraction of mapped length [0.95]");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = new Bytes();
|
||||||
|
var file = arguments[getopt.ind] == '-'? new File() : new File(arguments[getopt.ind]);
|
||||||
|
var a = [], h = {};
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
var is_pri = false;
|
||||||
|
if (parseInt(t[11]) < min_mapq) continue;
|
||||||
|
for (var i = 12; i < t.length; ++i)
|
||||||
|
if (t[i] == 'tp:A:P')
|
||||||
|
is_pri = true;
|
||||||
|
if (!is_pri) continue;
|
||||||
|
for (var i = 1; i <= 3; ++i)
|
||||||
|
t[i] = parseInt(t[i]);
|
||||||
|
for (var i = 6; i <= 8; ++i)
|
||||||
|
t[i] = parseInt(t[i]);
|
||||||
|
if (t[3] - t[2] < min_ovlp || t[8] - t[7] < min_ovlp || (t[3] - t[2]) / t[1] < min_frac)
|
||||||
|
continue;
|
||||||
|
var ctg = t[5], st = t[7], en = t[8];
|
||||||
|
while (a.length > 0) {
|
||||||
|
if (a[0][0] == ctg && a[0][2] > st)
|
||||||
|
break;
|
||||||
|
else a.shift();
|
||||||
|
}
|
||||||
|
for (var j = 0; j < a.length; ++j) {
|
||||||
|
if (a[j][3] == t[0]) continue;
|
||||||
|
var len = (en > a[j][2]? a[j][2] : en) - st;
|
||||||
|
if (len >= min_ovlp) {
|
||||||
|
var key = a[j][3] < t[0]? a[j][3] + "\t" + t[0] : t[0] + "\t" + a[j][3];
|
||||||
|
h[key] = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.push([ctg, st, en, t[0]]);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
file = new File(arguments[getopt.ind + 1]);
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
var key = t[0] < t[5]? t[0] + "\t" + t[5] : t[5] + "\t" + t[0];
|
||||||
|
if (h[key] > 0) h[key] = -h[key];
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
buf.destroy();
|
||||||
|
|
||||||
|
var n_ovlp = 0, n_missing = 0;
|
||||||
|
for (var key in h) {
|
||||||
|
++n_ovlp;
|
||||||
|
if (h[key] > 0) ++n_missing;
|
||||||
|
}
|
||||||
|
print(n_ovlp + " overlaps inferred from the reference mapping");
|
||||||
|
print(n_missing + " missed by the read overlapper");
|
||||||
|
print((100 * (1 - n_missing / n_ovlp)).toFixed(2) + "% sensitivity");
|
||||||
+4
-4
@@ -40,9 +40,9 @@ var re_cs = /([:=*+-])(\d+|[A-Za-z]+)/g;
|
|||||||
var c, min_cov_len = 10000, min_var_len = 50000, gap_thres = 50, min_mapq = 5;
|
var c, min_cov_len = 10000, min_var_len = 50000, gap_thres = 50, min_mapq = 5;
|
||||||
while ((c = getopt(arguments, "l:L:g:q:")) != null) {
|
while ((c = getopt(arguments, "l:L:g:q:")) != null) {
|
||||||
if (c == 'l') min_cov_len = parseInt(getopt.arg);
|
if (c == 'l') min_cov_len = parseInt(getopt.arg);
|
||||||
else if (c == 'L') min_var_len = parseInt(optarg.arg);
|
else if (c == 'L') min_var_len = parseInt(getopt.arg);
|
||||||
else if (c == 'g') gap_thres = parseInt(optarg.arg);
|
else if (c == 'g') gap_thres = parseInt(getopt.arg);
|
||||||
else if (c == 'q') min_mapq = parseInt(optarg.arg);
|
else if (c == 'q') min_mapq = parseInt(getopt.arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.length == getopt.ind) {
|
if (arguments.length == getopt.ind) {
|
||||||
@@ -55,7 +55,7 @@ if (arguments.length == getopt.ind) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var file = new File(arguments[getopt.ind]);
|
var file = arguments[getopt.ind] == '-'? new File() : new File(arguments[getopt.ind]);
|
||||||
var buf = new Bytes();
|
var buf = new Bytes();
|
||||||
var tot_len = 0, n_sub = [0, 0, 0], n_ins = [0, 0, 0, 0], n_del = [0, 0, 0, 0];
|
var tot_len = 0, n_sub = [0, 0, 0], n_ins = [0, 0, 0, 0], n_del = [0, 0, 0, 0];
|
||||||
|
|
||||||
|
|||||||
+25
-4
@@ -60,15 +60,29 @@ function print_lines(a, fmt) {
|
|||||||
|
|
||||||
function main(args) {
|
function main(args) {
|
||||||
var re = /(\d+)([MIDNSH])/g;
|
var re = /(\d+)([MIDNSH])/g;
|
||||||
var c, fmt = "bed";
|
var c, fmt = "bed", fn_name_conv = null;
|
||||||
while ((c = getopt(args, "f:")) != null) {
|
while ((c = getopt(args, "f:n:")) != null) {
|
||||||
if (c == 'f') fmt = getopt.arg;
|
if (c == 'f') fmt = getopt.arg;
|
||||||
|
else if (c == 'n') fn_name_conv = getopt.arg;
|
||||||
}
|
}
|
||||||
if (getopt.ind == args.length) {
|
if (getopt.ind == args.length) {
|
||||||
warn("Usage: k8 splice2bed.js <in.paf>");
|
warn("Usage: k8 splice2bed.js <in.paf>");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var conv = null;
|
||||||
|
if (fn_name_conv != null) {
|
||||||
|
conv = new Map();
|
||||||
|
var file = new File(fn_name_conv);
|
||||||
|
var buf = new Bytes();
|
||||||
|
while (file.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
conv.put(t[0], t[1]);
|
||||||
|
}
|
||||||
|
buf.destroy();
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
var file = new File(args[getopt.ind]);
|
var file = new File(args[getopt.ind]);
|
||||||
var buf = new Bytes();
|
var buf = new Bytes();
|
||||||
var a = [];
|
var a = [];
|
||||||
@@ -77,11 +91,17 @@ function main(args) {
|
|||||||
if (line.charAt(0) == '@') continue; // skip SAM header lines
|
if (line.charAt(0) == '@') continue; // skip SAM header lines
|
||||||
var t = line.split("\t");
|
var t = line.split("\t");
|
||||||
var is_pri = false, cigar = null, a1;
|
var is_pri = false, cigar = null, a1;
|
||||||
|
var qname = conv != null? conv.get(t[0]) : null;
|
||||||
|
if (qname != null) t[0] = qname;
|
||||||
|
if (t.length >= 10 && t[4] != '+' && t[4] != '-' && /^\d+/.test(t[1])) { // SAM
|
||||||
|
var flag = parseInt(t[1]);
|
||||||
|
if (flag&1) t[0] += '/' + (flag>>6&3);
|
||||||
|
}
|
||||||
if (a.length && a[0][3] != t[0]) {
|
if (a.length && a[0][3] != t[0]) {
|
||||||
print_lines(a, fmt);
|
print_lines(a, fmt);
|
||||||
a = [];
|
a = [];
|
||||||
}
|
}
|
||||||
if (t.length >= 12 && (t[4] == '+' || t[4] == '-')) {
|
if (t.length >= 12 && (t[4] == '+' || t[4] == '-')) { // PAF
|
||||||
for (var i = 12; i < t.length; ++i) {
|
for (var i = 12; i < t.length; ++i) {
|
||||||
if (t[i].substr(0, 5) == 'cg:Z:') {
|
if (t[i].substr(0, 5) == 'cg:Z:') {
|
||||||
cigar = t[i].substr(5);
|
cigar = t[i].substr(5);
|
||||||
@@ -90,7 +110,7 @@ function main(args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
a1 = [t[5], t[7], t[8], t[0], Math.floor(t[9]/t[10]*1000), t[4]];
|
a1 = [t[5], t[7], t[8], t[0], Math.floor(t[9]/t[10]*1000), t[4]];
|
||||||
} else if (t.length >= 10) {
|
} else if (t.length >= 10) { // SAM
|
||||||
var flag = parseInt(t[1]);
|
var flag = parseInt(t[1]);
|
||||||
if ((flag&4) || a[2] == '*') continue;
|
if ((flag&4) || a[2] == '*') continue;
|
||||||
cigar = t[5];
|
cigar = t[5];
|
||||||
@@ -122,6 +142,7 @@ function main(args) {
|
|||||||
print_lines(a, fmt);
|
print_lines(a, fmt);
|
||||||
buf.destroy();
|
buf.destroy();
|
||||||
file.close();
|
file.close();
|
||||||
|
if (conv != null) conv.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
main(arguments);
|
main(arguments);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#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)
|
||||||
#define MM_SEED_TANDEM (1ULL<<42)
|
#define MM_SEED_TANDEM (1ULL<<42)
|
||||||
|
#define MM_SEED_SELF (1ULL<<43)
|
||||||
|
|
||||||
#define MM_SEED_SEG_SHIFT 48
|
#define MM_SEED_SEG_SHIFT 48
|
||||||
#define MM_SEED_SEG_MASK (0xffULL<<(MM_SEED_SEG_SHIFT))
|
#define MM_SEED_SEG_MASK (0xffULL<<(MM_SEED_SEG_SHIFT))
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "mmpriv.h"
|
||||||
|
|
||||||
|
void mm_mapopt_init(mm_mapopt_t *opt)
|
||||||
|
{
|
||||||
|
memset(opt, 0, sizeof(mm_mapopt_t));
|
||||||
|
opt->seed = 11;
|
||||||
|
opt->mid_occ_frac = 2e-4f;
|
||||||
|
opt->sdust_thres = 0; // no SDUST masking
|
||||||
|
|
||||||
|
opt->min_cnt = 3;
|
||||||
|
opt->min_chain_score = 40;
|
||||||
|
opt->bw = 500;
|
||||||
|
opt->max_gap = 5000;
|
||||||
|
opt->max_gap_ref = -1;
|
||||||
|
opt->max_chain_skip = 25;
|
||||||
|
|
||||||
|
opt->mask_level = 0.5f;
|
||||||
|
opt->pri_ratio = 0.8f;
|
||||||
|
opt->best_n = 5;
|
||||||
|
|
||||||
|
opt->max_join_long = 20000;
|
||||||
|
opt->max_join_short = 2000;
|
||||||
|
opt->min_join_flank_sc = 1000;
|
||||||
|
|
||||||
|
opt->a = 2, opt->b = 4, opt->q = 4, opt->e = 2, opt->q2 = 24, opt->e2 = 1;
|
||||||
|
opt->zdrop = 400;
|
||||||
|
opt->end_bonus = -1;
|
||||||
|
opt->min_dp_max = opt->min_chain_score * opt->a;
|
||||||
|
opt->min_ksw_len = 200;
|
||||||
|
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
|
||||||
|
opt->mini_batch_size = 500000000;
|
||||||
|
|
||||||
|
opt->pe_ori = 0; // FF
|
||||||
|
opt->pe_bonus = 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm_mapopt_update(mm_mapopt_t *opt, const mm_idx_t *mi)
|
||||||
|
{
|
||||||
|
if ((opt->flag & MM_F_SPLICE_FOR) && (opt->flag & MM_F_SPLICE_REV))
|
||||||
|
opt->flag |= MM_F_SPLICE;
|
||||||
|
if (opt->mid_occ <= 0)
|
||||||
|
opt->mid_occ = mm_idx_cal_max_occ(mi, opt->mid_occ_frac);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm_mapopt_max_intron_len(mm_mapopt_t *opt, int max_intron_len)
|
||||||
|
{
|
||||||
|
if ((opt->flag & MM_F_SPLICE) && max_intron_len > 0)
|
||||||
|
opt->max_gap_ref = opt->bw = max_intron_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
||||||
|
{
|
||||||
|
if (preset == 0) {
|
||||||
|
mm_idxopt_init(io);
|
||||||
|
mm_mapopt_init(mo);
|
||||||
|
} else if (strcmp(preset, "ava-ont") == 0) {
|
||||||
|
io->flag = 0, io->k = 15, io->w = 5;
|
||||||
|
mo->flag |= MM_F_ALL_CHAINS | MM_F_NO_DIAG | MM_F_NO_DUAL | MM_F_NO_LJOIN;
|
||||||
|
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
|
||||||
|
} else if (strcmp(preset, "ava-pb") == 0) {
|
||||||
|
io->flag |= MM_I_HPC, io->k = 19, io->w = 5;
|
||||||
|
mo->flag |= MM_F_ALL_CHAINS | MM_F_NO_DIAG | MM_F_NO_DUAL | MM_F_NO_LJOIN;
|
||||||
|
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
|
||||||
|
} else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
|
||||||
|
io->flag |= MM_I_HPC, io->k = 19;
|
||||||
|
} else if (strcmp(preset, "map-ont") == 0) {
|
||||||
|
io->flag = 0, io->k = 15;
|
||||||
|
} else if (strcmp(preset, "asm5") == 0) {
|
||||||
|
io->flag = 0, io->k = 19, io->w = 19;
|
||||||
|
mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = 200;
|
||||||
|
mo->min_dp_max = 200;
|
||||||
|
mo->best_n = 50;
|
||||||
|
} else if (strcmp(preset, "asm10") == 0) {
|
||||||
|
io->flag = 0, io->k = 19, io->w = 19;
|
||||||
|
mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = 200;
|
||||||
|
mo->min_dp_max = 200;
|
||||||
|
mo->best_n = 50;
|
||||||
|
} else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) {
|
||||||
|
io->flag = 0, io->k = 21, io->w = 11;
|
||||||
|
mo->flag |= MM_F_SR | MM_F_FRAG_MODE | MM_F_NO_PRINT_2ND | MM_F_2_IO_THREADS | MM_F_HEAP_SORT;
|
||||||
|
mo->pe_ori = 0<<1|1; // FR
|
||||||
|
mo->a = 2, mo->b = 8, mo->q = 12, mo->e = 2, mo->q2 = 24, mo->e2 = 1;
|
||||||
|
mo->zdrop = 100;
|
||||||
|
mo->end_bonus = 10;
|
||||||
|
mo->max_frag_len = 800;
|
||||||
|
mo->max_gap = 100;
|
||||||
|
mo->bw = 100;
|
||||||
|
mo->pri_ratio = 0.5f;
|
||||||
|
mo->min_cnt = 2;
|
||||||
|
mo->min_chain_score = 25;
|
||||||
|
mo->min_dp_max = 40;
|
||||||
|
mo->best_n = 20;
|
||||||
|
mo->mid_occ = 1000;
|
||||||
|
mo->max_occ = 5000;
|
||||||
|
mo->mini_batch_size = 50000000;
|
||||||
|
} else if (strcmp(preset, "splice") == 0 || strcmp(preset, "cdna") == 0) {
|
||||||
|
io->flag = 0, io->k = 15, io->w = 5;
|
||||||
|
mo->flag |= MM_F_SPLICE | MM_F_SPLICE_FOR | MM_F_SPLICE_REV | MM_F_SPLICE_FLANK;
|
||||||
|
mo->max_gap = 2000, mo->max_gap_ref = mo->bw = 200000;
|
||||||
|
mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0;
|
||||||
|
mo->noncan = 9;
|
||||||
|
mo->zdrop = 200;
|
||||||
|
} else return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
|
||||||
|
{
|
||||||
|
if (mo->best_n < 0) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m -N must be no less than 0\033[0m\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if (mo->best_n == 0 && mm_verbose >= 2)
|
||||||
|
fprintf(stderr, "[WARNING]\033[1;31m '-N 0' reduces mapping accuracy. Please use '--secondary=no' instead.\033[0m\n");
|
||||||
|
if (mo->pri_ratio < 0.0f || mo->pri_ratio > 1.0f) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m -p must be within 0 and 1 (including 0 and 1)\033[0m\n");
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
if ((mo->flag & MM_F_FOR_ONLY) && (mo->flag & MM_F_REV_ONLY)) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m --for-only and --rev-only can't be applied at the same time\033[0m\n");
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
if ((mo->q != mo->q2 || mo->e != mo->e2) && !(mo->e > mo->e2 && mo->q + mo->e < mo->q2 + mo->e2)) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m dual gap penalties violating E1>E2 and O1+E1<O2+E2\033[0m\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if ((mo->q + mo->e) + (mo->q2 + mo->e2) > 127) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m scoring system violating ({-O}+{-E})+({-O2}+{-E2}) <= 127\033[0m\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+8
-2
@@ -81,10 +81,13 @@ This constructor accepts the following arguments:
|
|||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
mappy.Aligner.map(seq)
|
mappy.Aligner.map(seq, seq2=None)
|
||||||
|
|
||||||
This method aligns :code:`seq` against the index. It is a generator, *yielding*
|
This method aligns :code:`seq` against the index. It is a generator, *yielding*
|
||||||
a series of :code:`mappy.Alignment` objects.
|
a series of :code:`mappy.Alignment` objects. If :code:`seq2` is present, mappy
|
||||||
|
performs paired-end alignment, assuming the two ends are in the FR orientation.
|
||||||
|
Alignments of the two ends can be distinguished by the :code:`read_num` field
|
||||||
|
(see below).
|
||||||
|
|
||||||
Class mappy.Alignment
|
Class mappy.Alignment
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
@@ -118,6 +121,9 @@ properties:
|
|||||||
* **is_primary**: if the alignment is primary (typically the best and the first
|
* **is_primary**: if the alignment is primary (typically the best and the first
|
||||||
to generate)
|
to generate)
|
||||||
|
|
||||||
|
* **read_num**: read number that the alignment corresponds to; 1 for the first
|
||||||
|
read and 2 for the second read
|
||||||
|
|
||||||
* **cigar_str**: CIGAR string
|
* **cigar_str**: CIGAR string
|
||||||
|
|
||||||
* **cigar**: CIGAR returned as an array of shape :code:`(n_cigar,2)`. The two
|
* **cigar**: CIGAR returned as an array of shape :code:`(n_cigar,2)`. The two
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ typedef struct {
|
|||||||
int32_t blen, mlen, NM, ctg_len;
|
int32_t blen, mlen, NM, ctg_len;
|
||||||
uint8_t mapq, is_primary;
|
uint8_t mapq, is_primary;
|
||||||
int8_t strand, trans_strand;
|
int8_t strand, trans_strand;
|
||||||
|
int32_t seg_id;
|
||||||
int32_t n_cigar32;
|
int32_t n_cigar32;
|
||||||
uint32_t *cigar32;
|
uint32_t *cigar32;
|
||||||
} mm_hitpy_t;
|
} mm_hitpy_t;
|
||||||
@@ -32,6 +33,7 @@ static inline void mm_reg2hitpy(const mm_idx_t *mi, mm_reg1_t *r, mm_hitpy_t *h)
|
|||||||
h->NM = r->blen - r->mlen + r->p->n_ambi;
|
h->NM = r->blen - r->mlen + r->p->n_ambi;
|
||||||
h->trans_strand = r->p->trans_strand == 1? 1 : r->p->trans_strand == 2? -1 : 0;
|
h->trans_strand = r->p->trans_strand == 1? 1 : r->p->trans_strand == 2? -1 : 0;
|
||||||
h->is_primary = (r->id == r->parent);
|
h->is_primary = (r->id == r->parent);
|
||||||
|
h->seg_id = r->seg_id;
|
||||||
h->n_cigar32 = r->p->n_cigar;
|
h->n_cigar32 = r->p->n_cigar;
|
||||||
h->cigar32 = r->p->cigar;
|
h->cigar32 = r->p->cigar;
|
||||||
}
|
}
|
||||||
@@ -68,4 +70,35 @@ static inline void mm_reset_timer(void)
|
|||||||
mm_realtime0 = realtime();
|
mm_realtime0 = realtime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern unsigned char seq_comp_table[256];
|
||||||
|
static inline mm_reg1_t *mm_map_aux(const mm_idx_t *mi, const char *seq1, const char *seq2, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt)
|
||||||
|
{
|
||||||
|
if (seq2 == 0) {
|
||||||
|
return mm_map(mi, strlen(seq1), seq1, n_regs, b, opt, NULL);
|
||||||
|
} else {
|
||||||
|
int _n_regs[2];
|
||||||
|
mm_reg1_t *regs[2];
|
||||||
|
char *seq[2];
|
||||||
|
int i, len[2];
|
||||||
|
len[0] = strlen(seq1);
|
||||||
|
len[1] = strlen(seq2);
|
||||||
|
seq[0] = (char*)seq1;
|
||||||
|
seq[1] = strdup(seq2);
|
||||||
|
for (i = 0; i < len[1]>>1; ++i) {
|
||||||
|
int t = seq[1][len[1] - i - 1];
|
||||||
|
seq[1][len[1] - i - 1] = seq_comp_table[(uint8_t)seq[1][i]];
|
||||||
|
seq[1][i] = seq_comp_table[t];
|
||||||
|
}
|
||||||
|
if (len[1]&1) seq[1][len[1]>>1] = seq_comp_table[(uint8_t)seq[1][len[1]>>1]];
|
||||||
|
mm_map_frag(mi, 2, len, (const char**)seq, _n_regs, regs, b, opt, NULL);
|
||||||
|
for (i = 0; i < _n_regs[1]; ++i)
|
||||||
|
regs[1][i].rev = !regs[1][i].rev;
|
||||||
|
*n_regs = _n_regs[0] + _n_regs[1];
|
||||||
|
regs[0] = (mm_reg1_t*)realloc(regs[0], sizeof(mm_reg1_t) * (*n_regs));
|
||||||
|
memcpy(®s[0][_n_regs[0]], regs[1], _n_regs[1] * sizeof(mm_reg1_t));
|
||||||
|
free(regs[1]);
|
||||||
|
return regs[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-1
@@ -79,7 +79,6 @@ cdef extern from "minimap.h":
|
|||||||
|
|
||||||
mm_tbuf_t *mm_tbuf_init()
|
mm_tbuf_t *mm_tbuf_init()
|
||||||
void mm_tbuf_destroy(mm_tbuf_t *b)
|
void mm_tbuf_destroy(mm_tbuf_t *b)
|
||||||
mm_reg1_t *mm_map(const mm_idx_t *mi, int l_seq, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *name)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Helper header (because it is hard to expose mm_reg1_t with Cython)
|
# Helper header (because it is hard to expose mm_reg1_t with Cython)
|
||||||
@@ -92,11 +91,13 @@ cdef extern from "cmappy.h":
|
|||||||
int32_t blen, mlen, NM, ctg_len
|
int32_t blen, mlen, NM, ctg_len
|
||||||
uint8_t mapq, is_primary
|
uint8_t mapq, is_primary
|
||||||
int8_t strand, trans_strand
|
int8_t strand, trans_strand
|
||||||
|
int32_t seg_id
|
||||||
int32_t n_cigar32
|
int32_t n_cigar32
|
||||||
uint32_t *cigar32
|
uint32_t *cigar32
|
||||||
|
|
||||||
void mm_reg2hitpy(const mm_idx_t *mi, mm_reg1_t *r, mm_hitpy_t *h)
|
void mm_reg2hitpy(const mm_idx_t *mi, mm_reg1_t *r, mm_hitpy_t *h)
|
||||||
void mm_free_reg1(mm_reg1_t *r)
|
void mm_free_reg1(mm_reg1_t *r)
|
||||||
|
mm_reg1_t *mm_map_aux(const mm_idx_t *mi, const char *seq1, const char *seq2, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt)
|
||||||
|
|
||||||
ctypedef struct kstring_t:
|
ctypedef struct kstring_t:
|
||||||
unsigned l, m
|
unsigned l, m
|
||||||
|
|||||||
+10
-4
@@ -10,9 +10,10 @@ cdef class Alignment:
|
|||||||
cdef int _NM, _mlen, _blen
|
cdef int _NM, _mlen, _blen
|
||||||
cdef int8_t _strand, _trans_strand
|
cdef int8_t _strand, _trans_strand
|
||||||
cdef uint8_t _mapq, _is_primary
|
cdef uint8_t _mapq, _is_primary
|
||||||
|
cdef int _seg_id
|
||||||
cdef _ctg, _cigar # these are python objects
|
cdef _ctg, _cigar # these are python objects
|
||||||
|
|
||||||
def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand):
|
def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand, seg_id):
|
||||||
self._ctg = ctg if isinstance(ctg, str) else ctg.decode()
|
self._ctg = ctg if isinstance(ctg, str) else ctg.decode()
|
||||||
self._ctg_len, self._r_st, self._r_en = cl, cs, ce
|
self._ctg_len, self._r_st, self._r_en = cl, cs, ce
|
||||||
self._strand, self._q_st, self._q_en = strand, qs, qe
|
self._strand, self._q_st, self._q_en = strand, qs, qe
|
||||||
@@ -21,6 +22,7 @@ cdef class Alignment:
|
|||||||
self._cigar = cigar
|
self._cigar = cigar
|
||||||
self._is_primary = is_primary
|
self._is_primary = is_primary
|
||||||
self._trans_strand = trans_strand
|
self._trans_strand = trans_strand
|
||||||
|
self._seg_id = seg_id
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ctg(self): return self._ctg
|
def ctg(self): return self._ctg
|
||||||
@@ -64,6 +66,9 @@ cdef class Alignment:
|
|||||||
@property
|
@property
|
||||||
def cigar(self): return self._cigar
|
def cigar(self): return self._cigar
|
||||||
|
|
||||||
|
@property
|
||||||
|
def read_num(self): return self._seg_id + 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cigar_str(self):
|
def cigar_str(self):
|
||||||
return "".join(map(lambda x: str(x[0]) + 'MIDNSH'[x[1]], self._cigar))
|
return "".join(map(lambda x: str(x[0]) + 'MIDNSH'[x[1]], self._cigar))
|
||||||
@@ -125,7 +130,7 @@ cdef class Aligner:
|
|||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
return (self._idx != NULL)
|
return (self._idx != NULL)
|
||||||
|
|
||||||
def map(self, seq, buf=None):
|
def map(self, seq, seq2=None, buf=None):
|
||||||
cdef cmappy.mm_reg1_t *regs
|
cdef cmappy.mm_reg1_t *regs
|
||||||
cdef cmappy.mm_hitpy_t h
|
cdef cmappy.mm_hitpy_t h
|
||||||
cdef ThreadBuffer b
|
cdef ThreadBuffer b
|
||||||
@@ -134,7 +139,8 @@ cdef class Aligner:
|
|||||||
if self._idx is NULL: return None
|
if self._idx is NULL: return None
|
||||||
if buf is None: b = ThreadBuffer()
|
if buf is None: b = ThreadBuffer()
|
||||||
else: b = buf
|
else: b = buf
|
||||||
regs = cmappy.mm_map(self._idx, len(seq), str.encode(seq), &n_regs, b._b, &self.map_opt, NULL)
|
if seq2 is None: regs = cmappy.mm_map_aux(self._idx, str.encode(seq), NULL, &n_regs, b._b, &self.map_opt)
|
||||||
|
else: regs = cmappy.mm_map_aux(self._idx, str.encode(seq), str.encode(seq2), &n_regs, b._b, &self.map_opt)
|
||||||
|
|
||||||
for i in range(n_regs):
|
for i in range(n_regs):
|
||||||
cmappy.mm_reg2hitpy(self._idx, ®s[i], &h)
|
cmappy.mm_reg2hitpy(self._idx, ®s[i], &h)
|
||||||
@@ -142,7 +148,7 @@ cdef class Aligner:
|
|||||||
for k in range(h.n_cigar32):
|
for k in range(h.n_cigar32):
|
||||||
c = h.cigar32[k]
|
c = h.cigar32[k]
|
||||||
cigar.append([c>>4, c&0xf])
|
cigar.append([c>>4, c&0xf])
|
||||||
yield Alignment(h.ctg, h.ctg_len, h.ctg_start, h.ctg_end, h.strand, h.qry_start, h.qry_end, h.mapq, cigar, h.is_primary, h.mlen, h.blen, h.NM, h.trans_strand)
|
yield Alignment(h.ctg, h.ctg_len, h.ctg_start, h.ctg_end, h.strand, h.qry_start, h.qry_end, h.mapq, cigar, h.is_primary, h.mlen, h.blen, h.NM, h.trans_strand, h.seg_id)
|
||||||
cmappy.mm_free_reg1(®s[i])
|
cmappy.mm_free_reg1(®s[i])
|
||||||
free(regs)
|
free(regs)
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def readme():
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'mappy',
|
name = 'mappy',
|
||||||
version = '2.6',
|
version = '2.8',
|
||||||
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(),
|
||||||
@@ -33,13 +33,13 @@ setup(
|
|||||||
keywords = 'sequence-alignment',
|
keywords = 'sequence-alignment',
|
||||||
scripts = ['python/minimap2.py'],
|
scripts = ['python/minimap2.py'],
|
||||||
ext_modules = [Extension('mappy',
|
ext_modules = [Extension('mappy',
|
||||||
sources = [module_src, 'align.c', 'bseq.c', 'chain.c', 'format.c', 'hit.c', 'index.c', 'pe.c',
|
sources = [module_src, 'align.c', 'bseq.c', 'chain.c', 'format.c', 'hit.c', 'index.c', 'pe.c', 'options.c',
|
||||||
'ksw2_extd2_sse.c', 'ksw2_exts2_sse.c', 'ksw2_extz2_sse.c', 'ksw2_ll_sse.c',
|
'ksw2_extd2_sse.c', 'ksw2_exts2_sse.c', 'ksw2_extz2_sse.c', 'ksw2_ll_sse.c',
|
||||||
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c'],
|
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c'],
|
||||||
depends = ['minimap.h', 'bseq.h', 'kalloc.h', 'kdq.h', 'khash.h', 'kseq.h', 'ksort.h',
|
depends = ['minimap.h', 'bseq.h', 'kalloc.h', 'kdq.h', 'khash.h', 'kseq.h', 'ksort.h',
|
||||||
'ksw2.h', 'kthread.h', 'kvec.h', 'mmpriv.h', 'sdust.h',
|
'ksw2.h', 'kthread.h', 'kvec.h', 'mmpriv.h', 'sdust.h',
|
||||||
'python/cmappy.h', 'python/cmappy.pxd'],
|
'python/cmappy.h', 'python/cmappy.pxd'],
|
||||||
extra_compile_args = ['-msse4'], # WARNING: ancient x86_64 CPUs don't have SSE4
|
extra_compile_args = ['-DHAVE_KALLOC', '-msse4'], # WARNING: ancient x86_64 CPUs don't have SSE4
|
||||||
include_dirs = ['.'],
|
include_dirs = ['.'],
|
||||||
libraries = ['z', 'm', 'pthread'])],
|
libraries = ['z', 'm', 'pthread'])],
|
||||||
classifiers = [
|
classifiers = [
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#define __STDC_LIMIT_MACROS
|
||||||
#include "kvec.h"
|
#include "kvec.h"
|
||||||
#include "minimap.h"
|
#include "mmpriv.h"
|
||||||
|
|
||||||
unsigned char seq_nt4_table[256] = {
|
unsigned char seq_nt4_table[256] = {
|
||||||
0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
|
||||||
@@ -113,26 +114,26 @@ void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, i
|
|||||||
}
|
}
|
||||||
} else l = 0, tq.count = tq.front = 0, kmer_span = 0;
|
} else l = 0, tq.count = tq.front = 0, kmer_span = 0;
|
||||||
buf[buf_pos] = info; // need to do this here as appropriate buf_pos and buf[buf_pos] are needed below
|
buf[buf_pos] = info; // need to do this here as appropriate buf_pos and buf[buf_pos] are needed below
|
||||||
if (l == w + k - 1) { // special case for the first window - because identical k-mers are not stored yet
|
if (l == w + k - 1 && min.x != UINT64_MAX) { // special case for the first window - because identical k-mers are not stored yet
|
||||||
for (j = buf_pos + 1; j < w; ++j)
|
for (j = buf_pos + 1; j < w; ++j)
|
||||||
if (min.x == buf[j].x && buf[j].y != min.y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
|
if (min.x == buf[j].x && buf[j].y != min.y) kv_push(mm128_t, km, *p, buf[j]);
|
||||||
for (j = 0; j < buf_pos; ++j)
|
for (j = 0; j < buf_pos; ++j)
|
||||||
if (min.x == buf[j].x && buf[j].y != min.y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
|
if (min.x == buf[j].x && buf[j].y != min.y) kv_push(mm128_t, km, *p, buf[j]);
|
||||||
}
|
}
|
||||||
if (info.x <= min.x) { // a new minimum; then write the old min
|
if (info.x <= min.x) { // a new minimum; then write the old min
|
||||||
if (l >= w + k && min.y != UINT64_MAX) kv_push(mm128_t, km, *p, min);
|
if (l >= w + k && min.x != UINT64_MAX) kv_push(mm128_t, km, *p, min);
|
||||||
min = info, min_pos = buf_pos;
|
min = info, min_pos = buf_pos;
|
||||||
} else if (buf_pos == min_pos) { // old min has moved outside the window
|
} else if (buf_pos == min_pos) { // old min has moved outside the window
|
||||||
if (l >= w + k - 1) kv_push(mm128_t, km, *p, min);
|
if (l >= w + k - 1 && min.x != UINT64_MAX) kv_push(mm128_t, km, *p, min);
|
||||||
for (j = buf_pos + 1, min.x = UINT64_MAX; j < w; ++j) // the two loops are necessary when there are identical k-mers
|
for (j = buf_pos + 1, min.x = UINT64_MAX; j < w; ++j) // the two loops are necessary when there are identical k-mers
|
||||||
if (min.x >= buf[j].x) min = buf[j], min_pos = j; // >= is important s.t. min is always the closest k-mer
|
if (min.x >= buf[j].x) min = buf[j], min_pos = j; // >= is important s.t. min is always the closest k-mer
|
||||||
for (j = 0; j <= buf_pos; ++j)
|
for (j = 0; j <= buf_pos; ++j)
|
||||||
if (min.x >= buf[j].x) min = buf[j], min_pos = j;
|
if (min.x >= buf[j].x) min = buf[j], min_pos = j;
|
||||||
if (l >= w + k - 1) { // write identical k-mers
|
if (l >= w + k - 1 && min.x != UINT64_MAX) { // write identical k-mers
|
||||||
for (j = buf_pos + 1; j < w; ++j) // these two loops make sure the output is sorted
|
for (j = buf_pos + 1; j < w; ++j) // these two loops make sure the output is sorted
|
||||||
if (min.x == buf[j].x && min.y != buf[j].y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
|
if (min.x == buf[j].x && min.y != buf[j].y) kv_push(mm128_t, km, *p, buf[j]);
|
||||||
for (j = 0; j <= buf_pos; ++j)
|
for (j = 0; j <= buf_pos; ++j)
|
||||||
if (min.x == buf[j].x && min.y != buf[j].y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
|
if (min.x == buf[j].x && min.y != buf[j].y) kv_push(mm128_t, km, *p, buf[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (++buf_pos == w) buf_pos = 0;
|
if (++buf_pos == w) buf_pos = 0;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+17
-9
@@ -268,18 +268,10 @@
|
|||||||
Title = {Mason -- a read simulator for second generation sequencing data},
|
Title = {Mason -- a read simulator for second generation sequencing data},
|
||||||
Year = {2010}}
|
Year = {2010}}
|
||||||
|
|
||||||
@article{Langmead:2012fk,
|
|
||||||
Author = {Langmead, Ben and Salzberg, Steven L},
|
|
||||||
Journal = {Nat Methods},
|
|
||||||
Pages = {357-9},
|
|
||||||
Title = {Fast gapped-read alignment with Bowtie 2},
|
|
||||||
Volume = {9},
|
|
||||||
Year = {2012}}
|
|
||||||
|
|
||||||
@article{Zaharia:2011aa,
|
@article{Zaharia:2011aa,
|
||||||
Author = {Zaharia, Matei and others},
|
Author = {Zaharia, Matei and others},
|
||||||
Journal = {arXiv:1111:5572},
|
Journal = {arXiv:1111:5572},
|
||||||
Title = {Faster and More Accurate Sequence Alignment with SNAP},
|
Title = {Faster and More Accurate Sequence Alignment with {SNAP}},
|
||||||
Year = {2011}}
|
Year = {2011}}
|
||||||
|
|
||||||
@article{Irimia:2008aa,
|
@article{Irimia:2008aa,
|
||||||
@@ -305,3 +297,19 @@
|
|||||||
Title = {Versatile and open software for comparing large genomes},
|
Title = {Versatile and open software for comparing large genomes},
|
||||||
Volume = {5},
|
Volume = {5},
|
||||||
Year = {2004}}
|
Year = {2004}}
|
||||||
|
|
||||||
|
@article {Li223297,
|
||||||
|
author = {Li, Heng and others},
|
||||||
|
title = {New synthetic-diploid benchmark for accurate variant calling evaluation},
|
||||||
|
year = {2017},
|
||||||
|
note = {doi:10.1101/223297},
|
||||||
|
journal = {bioRxiv}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{Berlin:2015xy,
|
||||||
|
Author = {Berlin, Konstantin and others},
|
||||||
|
Journal = {Nat Biotechnol},
|
||||||
|
Pages = {623-30},
|
||||||
|
Title = {Assembling large genomes with single-molecule sequencing and locality-sensitive hashing},
|
||||||
|
Volume = {33},
|
||||||
|
Year = {2015}}
|
||||||
|
|||||||
+65
-16
@@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
\usepackage{natbib}
|
\usepackage{natbib}
|
||||||
\bibliographystyle{apalike}
|
\bibliographystyle{apalike}
|
||||||
\usepackage{hyperref}
|
|
||||||
|
|
||||||
\DeclareMathOperator*{\argmax}{argmax}
|
\DeclareMathOperator*{\argmax}{argmax}
|
||||||
|
|
||||||
@@ -138,7 +137,7 @@ $h=50$; even if the heuristic fails, the optimal chain is often close.
|
|||||||
|
|
||||||
\subsubsection{Backtracking}
|
\subsubsection{Backtracking}
|
||||||
Let $P(i)$ be the index of the best predecessor of anchor $i$. It equals 0 if
|
Let $P(i)$ be the index of the best predecessor of anchor $i$. It equals 0 if
|
||||||
$f(i)=w_i$ or $\argmax_j\{f(j)+\eta(j,i)-\gamma(j,i)\}$ otherwise. For each
|
$f(i)=w_i$ or $\argmax_j\{f(j)+\alpha(j,i)-\beta(j,i)\}$ otherwise. For each
|
||||||
anchor $i$ in the descending order of $f(i)$, we apply $P(\cdot)$ repeatedly to
|
anchor $i$ in the descending order of $f(i)$, we apply $P(\cdot)$ repeatedly to
|
||||||
find its predecessor and mark each visited $i$ as `used', until $P(i)=0$ or we
|
find its predecessor and mark each visited $i$ as `used', until $P(i)=0$ or we
|
||||||
reach an already `used' $i$. This way we find all chains with no anchors used
|
reach an already `used' $i$. This way we find all chains with no anchors used
|
||||||
@@ -157,6 +156,53 @@ add the chain to $Q$. In the end, $Q$ contains all the primary chains. We did
|
|||||||
not choose a more sophisticated data structure (e.g. range tree or k-d tree)
|
not choose a more sophisticated data structure (e.g. range tree or k-d tree)
|
||||||
because this step is not the performance bottleneck.
|
because this step is not the performance bottleneck.
|
||||||
|
|
||||||
|
\subsubsection{Estimating per-base sequence divergence}
|
||||||
|
Suppose a query sequence harbors $n$ seeds of length $k$, $m$ of which are
|
||||||
|
present in a chain. We want to estimate the sequence divergence $\epsilon$
|
||||||
|
between the query and the reference sequences in the chain. This is useful
|
||||||
|
when base-level alignment is too expensive to perform.
|
||||||
|
|
||||||
|
If we model substitutions with a homogeneous Poisson process along the query
|
||||||
|
sequence, the probablity of seeing $k$ consecutive bases without substitutions
|
||||||
|
is $e^{-k\epsilon}$. On the assumption that all $k$-mers are independent of
|
||||||
|
each other, the likelihood function of $\epsilon$ is
|
||||||
|
\[
|
||||||
|
\mathcal{L}(\epsilon|n,m,k)=e^{-m\cdot k\epsilon}(1-e^{-k\epsilon})^{n-m}
|
||||||
|
\]
|
||||||
|
The maximum likelihood estimate of $\epsilon$ is
|
||||||
|
\[
|
||||||
|
\hat{\epsilon}=\frac{1}{k}\log\frac{n}{m}
|
||||||
|
\]
|
||||||
|
In reality, sequencing errors are sometimes clustered and $k$-mers are not
|
||||||
|
independent of each other, especially when we take minimizers as seeds. These
|
||||||
|
violate the assumptions in the derivation above. As a result, $\hat{\epsilon}$
|
||||||
|
is only approximate and can be biased. It also ignores long deletions from the
|
||||||
|
reference sequence. In practice, fortunately, $\hat{\epsilon}$ is often close
|
||||||
|
to and strongly correlated with the sequence divergence estimated from
|
||||||
|
base-level alignments. On the several datasets used in
|
||||||
|
Section~\ref{sec:long-genomic}, the Spearman correlation coefficient is around
|
||||||
|
$0.9$.
|
||||||
|
|
||||||
|
\subsubsection{Indexing with homopolymer compressed $k$-mers}
|
||||||
|
SmartDenovo
|
||||||
|
(\href{https://github.com/ruanjue/smartdenovo}{https://github.com/ruanjue/smartdenovo};
|
||||||
|
J Ruan, personal communication) indexes reads with homopolymer-compressed (HPC)
|
||||||
|
$k$-mers and finds the strategy improves overlap sensitivity for SMRT reads.
|
||||||
|
Minimap2 adopts the same heuristic.
|
||||||
|
|
||||||
|
The HPC string of a string $s$, denoted by ${\rm HPC}(s)$, is constructed by
|
||||||
|
contracting homopolymers in $s$ to a single base. An HPC $k$-mer of $s$ is a
|
||||||
|
$k$-long substring of ${\rm HPC}(s)$. For example, suppose $s={\tt GGATTTTCCA}$,
|
||||||
|
${\rm HPC}(s)={\tt GATCA}$ and the first HPC 4-mer is ${\tt GATC}$.
|
||||||
|
|
||||||
|
To demonstrate the effectiveness of HPC $k$-mers, we performed read overlapping
|
||||||
|
for the example {\it E. coli} SMRT reads from PBcR~\citep{Berlin:2015xy}, using
|
||||||
|
different types of $k$-mers. With normal 15bp minimizers per 5bp window,
|
||||||
|
minimap2 finds 90.9\% of $\ge$2kb overlaps inferred from the read-to-reference
|
||||||
|
alignment. With HPC 19-mers, minimap2 finds 97.4\% of overlaps. It achieves this
|
||||||
|
higher sensitivity by indexing 1/3 fewer minimizers, which further helps
|
||||||
|
performance. HPC-based indexing reduces the sensitivity for ONT reads, though.
|
||||||
|
|
||||||
\subsection{Aligning genomic DNA}\label{sec:genomic}
|
\subsection{Aligning genomic DNA}\label{sec:genomic}
|
||||||
|
|
||||||
\subsubsection{Alignment with 2-piece affine gap cost}
|
\subsubsection{Alignment with 2-piece affine gap cost}
|
||||||
@@ -397,7 +443,7 @@ consistent paired-end alignments.
|
|||||||
|
|
||||||
\section{Results}
|
\section{Results}
|
||||||
|
|
||||||
\subsection{Aligning long genomic reads}
|
\subsection{Aligning long genomic reads}\label{sec:long-genomic}
|
||||||
|
|
||||||
\begin{figure}[!tb]
|
\begin{figure}[!tb]
|
||||||
\centering
|
\centering
|
||||||
@@ -500,14 +546,18 @@ more junctions with a higher percentage being exactly or approximately correct.
|
|||||||
Minimap2 is over 40 times faster than GMAP and SpAln. While STAR is close to
|
Minimap2 is over 40 times faster than GMAP and SpAln. While STAR is close to
|
||||||
minimap2 in speed, it does not work well with noisy reads.
|
minimap2 in speed, it does not work well with noisy reads.
|
||||||
|
|
||||||
We have also evaluated spliced aligners on public Iso-Seq data (human Alzheimer
|
We have also evaluated spliced aligners on a human Nanopore Direct RNA-seq
|
||||||
brain from \href{http://bit.ly/isoseqpub}{http://bit.ly/isoseqpub}). The
|
dataset (\href{http://bit.ly/na12878ont}{http://bit.ly/na12878ont}). Minimap2
|
||||||
observation is similar: minimap2 is faster at higher junction accuracy.
|
aligned 10 million reads in $<$1 wall-clock hour using 16 CPU cores. 94.2\% of
|
||||||
On a private Nanopore Direct RNA data set with $\sim$17\% sequencing error rate
|
aligned splice junctions consistent with gene annotations. In comparison,
|
||||||
(N. Loman, personal communication), minimap2 aligned 96\,467 introns
|
GMAP under option `-k 14 -n 0 --min-intronlength 30 --cross-species' is 160
|
||||||
from 37\,068 mapped reads with 95.4\% of them consistent with human gene
|
times slower; 68.7\% of GMAP junctions are found in known gene annotations. The
|
||||||
annotations. In comparison, only 74.8\% of GMAP introns found in known gene
|
percentage increases to 84.1\% if an aligned junction within 10bp from an
|
||||||
annotations.
|
annotated junction is considered to be correct. On a public Iso-Seq dataset
|
||||||
|
(human Alzheimer brain from
|
||||||
|
\href{http://bit.ly/isoseqpub}{http://bit.ly/isoseqpub}), minimap2 is also
|
||||||
|
faster at higher junction accuracy in comparison to other aligners in
|
||||||
|
Table~\ref{tab:intron}.
|
||||||
|
|
||||||
We noted that GMAP and SpAln have not been optimized for noisy reads. We are
|
We noted that GMAP and SpAln have not been optimized for noisy reads. We are
|
||||||
showing the best setting we have experimented, but their developers should be
|
showing the best setting we have experimented, but their developers should be
|
||||||
@@ -551,8 +601,7 @@ with GATK HaplotypeCaller v3.5~\citep{Depristo:2011vn}. This run was sequenced
|
|||||||
from experimentally mixed CHM1 and CHM13 cell lines. Both of them are homozygous
|
from experimentally mixed CHM1 and CHM13 cell lines. Both of them are homozygous
|
||||||
across the whole genome and have been \emph{de novo} assembled with SMRT reads
|
across the whole genome and have been \emph{de novo} assembled with SMRT reads
|
||||||
to high quality. This allowed us to construct an independent truth variant
|
to high quality. This allowed us to construct an independent truth variant
|
||||||
data set
|
dataset~\citep{Li223297} for
|
||||||
(\href{https://github.com/lh3/CHM-eval}{https://github.com/lh3/CHM-eval}) for
|
|
||||||
ERR1341796. In this evaluation, minimap2 has higher SNP false negative rate
|
ERR1341796. In this evaluation, minimap2 has higher SNP false negative rate
|
||||||
(FNR; 2.5\% of minimap2 vs 2.2\% of BWA-MEM), but fewer false positive SNPs per
|
(FNR; 2.5\% of minimap2 vs 2.2\% of BWA-MEM), but fewer false positive SNPs per
|
||||||
million bases (FPPM; 3.0 vs 3.9), lower 2--50bp INDEL FNR (7.3\% vs 7.5\%) and
|
million bases (FPPM; 3.0 vs 3.9), lower 2--50bp INDEL FNR (7.3\% vs 7.5\%) and
|
||||||
@@ -597,7 +646,7 @@ uniqueness and reduce unsuccessful extensions. Minimap2 indexes reference
|
|||||||
k-mers with a hash table instead. Such fixed-length seeds are inferior to
|
k-mers with a hash table instead. Such fixed-length seeds are inferior to
|
||||||
variable-length seeds in theory, but can be computed much more efficiently in
|
variable-length seeds in theory, but can be computed much more efficiently in
|
||||||
practice. When a query sequence has multiple seed hits, we can afford to skip
|
practice. When a query sequence has multiple seed hits, we can afford to skip
|
||||||
some highly repetitive seeds without affecting the final accuracy. This further
|
highly repetitive seeds without affecting the final accuracy. This further
|
||||||
alleviates the concern with the uniqueness of seeds. Hash table is the ideal
|
alleviates the concern with the uniqueness of seeds. Hash table is the ideal
|
||||||
data structure for mapping long query sequences.
|
data structure for mapping long query sequences.
|
||||||
|
|
||||||
@@ -605,8 +654,8 @@ data structure for mapping long query sequences.
|
|||||||
We owe a debt of gratitude to H. Suzuki and M. Kasahara for releasing their
|
We owe a debt of gratitude to H. Suzuki and M. Kasahara for releasing their
|
||||||
masterpiece and insightful notes before formal publication. We thank M.
|
masterpiece and insightful notes before formal publication. We thank M.
|
||||||
Schatz, P. Rescheneder and F. Sedlazeck for pointing out the limitation of
|
Schatz, P. Rescheneder and F. Sedlazeck for pointing out the limitation of
|
||||||
BWA-MEM. We are also grateful to early minimap2 testers who have greatly helped
|
BWA-MEM. We are also grateful to minimap2 users who have greatly helped to
|
||||||
to suggest features and to fix various issues.
|
suggest features and to fix various issues.
|
||||||
|
|
||||||
\bibliography{minimap2}
|
\bibliography{minimap2}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user