mirror of
https://github.com/lh3/minimap2.git
synced 2026-09-25 03:18:11 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7358a1ead1 | ||
|
|
32f552957e | ||
|
|
a05edfa5ec | ||
|
|
8e81145817 | ||
|
|
e37f5ffe39 | ||
|
|
8a1d52bcbe | ||
|
|
f7271a7c24 | ||
|
|
70393eb46e | ||
|
|
9d049f0562 | ||
|
|
5180b70ff3 | ||
|
|
2392e54fe2 | ||
|
|
629c11728e | ||
|
|
59488f0271 | ||
|
|
7e33fde82b | ||
|
|
c4fe52fb07 | ||
|
|
ead1cfbaca | ||
|
|
83a535f148 | ||
|
|
f3af29a8aa | ||
|
|
cf7eaef367 | ||
|
|
2411887d8e | ||
|
|
1a8373bb84 | ||
|
|
161ae7ff73 | ||
|
|
8a6edab847 | ||
|
|
15118dd521 | ||
|
|
2546999639 | ||
|
|
52fafe0fed | ||
|
|
5f449c5cae | ||
|
|
b046052d82 | ||
|
|
5cc3d2239f | ||
|
|
581f2d7123 | ||
|
|
52dbd439bc | ||
|
|
260a68d232 | ||
|
|
177eef259d | ||
|
|
459ce04c84 | ||
|
|
e6cce019e4 | ||
|
|
7025b0b941 | ||
|
|
fe6a0bb337 | ||
|
|
3f7147864b | ||
|
|
c83589b9ea | ||
|
|
ce7a59f412 | ||
|
|
15471bd629 | ||
|
|
ca19463268 | ||
|
|
4f8d1bc360 | ||
|
|
1776c0c645 | ||
|
|
9febf532c1 | ||
|
|
cec23131e4 | ||
|
|
ef09ccf104 | ||
|
|
e74dfd1aa9 | ||
|
|
f31705bb4a | ||
|
|
41d7ccb191 | ||
|
|
34a41197d7 | ||
|
|
9626b3e716 | ||
|
|
379728726a | ||
|
|
4f91558160 | ||
|
|
ec3bc6efd7 | ||
|
|
8ec8866100 | ||
|
|
9e7247cff9 | ||
|
|
cd66777bfb | ||
|
|
5d7d25e92d | ||
|
|
2a3793bbd2 | ||
|
|
f97008a10e | ||
|
|
10502e2a78 | ||
|
|
4422c0c6f9 | ||
|
|
42a11e1d58 | ||
|
|
76df351fa8 | ||
|
|
d065d3bead | ||
|
|
ac146fe7bc | ||
|
|
6c96078ed0 | ||
|
|
bbb4f97e52 | ||
|
|
b7f4d8a0f4 | ||
|
|
e81927e7a1 | ||
|
|
f7dc5799c5 | ||
|
|
817cb81cb0 | ||
|
|
0f5608c4a4 | ||
|
|
e8823a3709 | ||
|
|
7edeec67b0 | ||
|
|
feb92d32ea | ||
|
|
cdbd96be0c | ||
|
|
ba52c79024 | ||
|
|
cd9ccfa069 | ||
|
|
86b716448c | ||
|
|
9ab95be1bb | ||
|
|
b51e859945 | ||
|
|
a9037dc16c | ||
|
|
9729fa99ad | ||
|
|
b6ff332de1 | ||
|
|
77abafaaf3 | ||
|
|
507d39af15 | ||
|
|
827ca4b461 | ||
|
|
d3dde2fdd4 | ||
|
|
7db2e8d21a | ||
|
|
0b41dd26a2 | ||
|
|
2b47846cd6 | ||
|
|
67dd906a80 | ||
|
|
1b0bb7b0ba | ||
|
|
1c4b7e8a48 | ||
|
|
ecbc399fa2 | ||
|
|
4dfd495cc2 | ||
|
|
194b457e79 | ||
|
|
75c8933511 | ||
|
|
1025993469 | ||
|
|
a3253d1a6b | ||
|
|
2da649d1d7 | ||
|
|
f995f55610 | ||
|
|
c9874e2dc5 | ||
|
|
28a37a017a | ||
|
|
ccb0f7b05d | ||
|
|
66db9da7d8 | ||
|
|
cd2b19035b | ||
|
|
9c0e2c67f8 | ||
|
|
da7109fd29 | ||
|
|
2b3403f094 | ||
|
|
3e16e4e39d | ||
|
|
f47e8a525e | ||
|
|
c172df7d2d | ||
|
|
9e6fdd376b | ||
|
|
29f67a1666 | ||
|
|
adde608a42 | ||
|
|
f10dff78dc | ||
|
|
d97bba9f27 | ||
|
|
50775362bb | ||
|
|
0a5e386359 | ||
|
|
cb56fb762a | ||
|
|
e2451e497a | ||
|
|
d2de282d21 | ||
|
|
48cb80ea94 | ||
|
|
6a4b9f9082 | ||
|
|
a7a01fe5bd | ||
|
|
9dceae59a0 | ||
|
|
20a3987082 | ||
|
|
eb3ed6993d | ||
|
|
7996f04008 | ||
|
|
d2e14705e7 | ||
|
|
24f50f38e8 | ||
|
|
04e015d803 | ||
|
|
040f74102c | ||
|
|
cdb7857841 | ||
|
|
3c0d05d272 | ||
|
|
47b646acbf | ||
|
|
a79cb3e991 | ||
|
|
367aed4271 | ||
|
|
081df6ac7d | ||
|
|
a3e7a575fb | ||
|
|
d90583b83c | ||
|
|
7fc03b0c32 | ||
|
|
20c104ce8d | ||
|
|
238b6bb3ea | ||
|
|
e026e18439 | ||
|
|
58c2251b18 | ||
|
|
03dc8d5d97 | ||
|
|
5cb61f8ee6 | ||
|
|
c16a1742a3 | ||
|
|
4bd5a018c2 | ||
|
|
05974c80f1 | ||
|
|
7bc87b4175 | ||
|
|
6762368cf0 | ||
|
|
c2aec88b84 | ||
|
|
97f67a2a0a | ||
|
|
189555503a | ||
|
|
69af86657e | ||
|
|
49c6d83a8e | ||
|
|
f64e426a5a | ||
|
|
2bb8cbbeef | ||
|
|
e80759c97a | ||
|
|
f4c844b143 | ||
|
|
be171aa2dc | ||
|
|
cdc730d573 | ||
|
|
6420acca6d | ||
|
|
371bc9513a | ||
|
|
169216bfff | ||
|
|
6b391e3373 | ||
|
|
55e39c2d30 | ||
|
|
90b7b83ec7 | ||
|
|
d431dc0181 | ||
|
|
ccf1680aaf | ||
|
|
ea84fc0a53 | ||
|
|
19208fb06b | ||
|
|
e02bebd96d | ||
|
|
32ab6ce15b | ||
|
|
1739a260fb | ||
|
|
aaf3233818 | ||
|
|
8b05880f73 | ||
|
|
eba237f39d | ||
|
|
a8e1e3cbb8 | ||
|
|
597212b9f3 | ||
|
|
30abcf3cf9 | ||
|
|
48e230f40d | ||
|
|
c404f49569 | ||
|
|
cf2bae6e9b | ||
|
|
5b2fdfff9c | ||
|
|
ea2b1c5b2a | ||
|
|
eef1cee9b7 | ||
|
|
2c52364527 | ||
|
|
128476efc9 | ||
|
|
1b3a6a0fe5 | ||
|
|
83a8ee7038 | ||
|
|
62bbadf668 | ||
|
|
91f548b497 | ||
|
|
cdaf46665a | ||
|
|
6596c63dcd | ||
|
|
59f23f7579 | ||
|
|
5e55e397e9 | ||
|
|
88c421e8de | ||
|
|
3db5bfe6e5 | ||
|
|
83dfdd5f50 | ||
|
|
8a2b1cd4c9 | ||
|
|
1ede8ca170 | ||
|
|
13981404e2 | ||
|
|
fd64dd26f6 | ||
|
|
24df95e4b8 | ||
|
|
a8ee48c2ce | ||
|
|
09e089c3dc | ||
|
|
e46cbb7d84 | ||
|
|
57ec73ec6c | ||
|
|
9e27575387 | ||
|
|
b4ad8d8bf0 | ||
|
|
e315b9fada | ||
|
|
42baf287a4 | ||
|
|
2ceba22a7a | ||
|
|
9ed56b4a25 | ||
|
|
ecb6c5c36c | ||
|
|
377c7099a8 | ||
|
|
51e2abfa60 | ||
|
|
7b0a49732e |
@@ -0,0 +1,21 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
compiler: [gcc, clang]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout minimap2
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Compile with ${{ matrix.compiler }}
|
||||||
|
run: make CC=${{ matrix.compiler }}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "lib/simde"]
|
||||||
|
path = lib/simde
|
||||||
|
url = https://github.com/nemequ/simde.git
|
||||||
+5
-1
@@ -6,6 +6,10 @@ matrix:
|
|||||||
- language: c
|
- language: c
|
||||||
compiler: clang
|
compiler: clang
|
||||||
script: make
|
script: make
|
||||||
|
- arch: arm64
|
||||||
|
language: c
|
||||||
|
compiler: gcc
|
||||||
|
script: make arm_neon=1 aarch64=1
|
||||||
- language: python
|
- language: python
|
||||||
python: "2.7"
|
python: "2.7"
|
||||||
before_install: pip install cython
|
before_install: pip install cython
|
||||||
@@ -15,6 +19,6 @@ matrix:
|
|||||||
before_install: pip install cython
|
before_install: pip install cython
|
||||||
script: python setup.py build_ext
|
script: python setup.py build_ext
|
||||||
- language: python
|
- language: python
|
||||||
python: "3.6"
|
python: "3.9"
|
||||||
before_install: pip install cython
|
before_install: pip install cython
|
||||||
script: python setup.py build_ext
|
script: python setup.py build_ext
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#### 1. Alignment different with option `-a` or `-c`?
|
||||||
|
|
||||||
|
Without `-a`, `-c` or `--cs`, minimap2 only finds *approximate* mapping
|
||||||
|
locations without detailed base alignment. In particular, the start and end
|
||||||
|
positions of the alignment are impricise. With one of those options, minimap2
|
||||||
|
will perform base alignment, which is generally more accurate but is much
|
||||||
|
slower.
|
||||||
|
|
||||||
|
#### 2. How to map Illumina short reads to noisy long reads?
|
||||||
|
|
||||||
|
No good solutions. The better approach is to assemble short reads into contigs
|
||||||
|
and then map noisy reads to contigs.
|
||||||
|
|
||||||
|
#### 3. The output SAM doesn't have a header.
|
||||||
|
|
||||||
|
By default, minimap2 indexes 4 billion reference bases (4Gb) in a batch and map
|
||||||
|
all reads against each reference batch. Given a reference longer than 4Gb,
|
||||||
|
minimap2 is unable to see all the sequences and thus can't produce a correct
|
||||||
|
SAM header. In this case, minimap2 doesn't output any SAM header. There are two
|
||||||
|
solutions to this issue. First, you may increase option `-I` to, for example,
|
||||||
|
`-I8g` to index more reference bases in a batch. This is preferred if your
|
||||||
|
machine has enough memory. Second, if your machines doesn't have enough memory
|
||||||
|
to hold the reference index, you can use the `--split-prefix` option in a
|
||||||
|
command line like:
|
||||||
|
```sh
|
||||||
|
minimap2 -ax map-ont --split-prefix=tmp ref.fa reads.fq
|
||||||
|
```
|
||||||
|
This second approach uses less memory, but it is slower and requires temporary
|
||||||
|
disk space.
|
||||||
|
|
||||||
|
#### 4. The output SAM is malformatted.
|
||||||
|
|
||||||
|
This typically happens when you use nohup to wrap a minimap2 command line.
|
||||||
|
Nohup is discouraged as it breaks piping. If you have to use nohup, please
|
||||||
|
specify an output file with option `-o`.
|
||||||
|
|
||||||
|
#### 5. How to output one alignment per read?
|
||||||
|
|
||||||
|
You can use `--secondary=no` to suppress secondary alignments (aka multiple
|
||||||
|
mappings), but you can't suppress supplementary alignment (aka split or
|
||||||
|
chimeric alignment) this way. You can use samtools to filter out these
|
||||||
|
alignments:
|
||||||
|
```sh
|
||||||
|
minimap2 -ax map-out ref.fa reads.fq | samtools view -F0x900
|
||||||
|
```
|
||||||
|
However, this is discouraged as supplementary alignment is informative.
|
||||||
@@ -4,7 +4,6 @@ include ksw2_dispatch.c
|
|||||||
include main.c
|
include main.c
|
||||||
include README.md
|
include README.md
|
||||||
include sse2neon/emmintrin.h
|
include sse2neon/emmintrin.h
|
||||||
include python/mappy.c
|
|
||||||
include python/cmappy.h
|
include python/cmappy.h
|
||||||
include python/cmappy.pxd
|
include python/cmappy.pxd
|
||||||
include python/mappy.pyx
|
include python/mappy.pyx
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra
|
CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra
|
||||||
CPPFLAGS= -DHAVE_KALLOC
|
CPPFLAGS= -DHAVE_KALLOC
|
||||||
INCLUDES=
|
INCLUDES=
|
||||||
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o options.o index.o chain.o align.o hit.o map.o format.o pe.o esterr.o splitidx.o ksw2_ll_sse.o
|
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o options.o index.o \
|
||||||
|
lchain.o align.o hit.o seed.o map.o format.o pe.o esterr.o splitidx.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
|
||||||
@@ -22,6 +24,16 @@ else #if aarch64 is defined
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(asan),)
|
||||||
|
CFLAGS+=-fsanitize=address
|
||||||
|
LIBS+=-fsanitize=address
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(tsan),)
|
||||||
|
CFLAGS+=-fsanitize=thread
|
||||||
|
LIBS+=-fsanitize=thread
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY:all extra clean depend
|
.PHONY:all extra clean depend
|
||||||
.SUFFIXES:.c .o
|
.SUFFIXES:.c .o
|
||||||
|
|
||||||
@@ -93,26 +105,28 @@ depend:
|
|||||||
|
|
||||||
# DO NOT DELETE
|
# DO NOT DELETE
|
||||||
|
|
||||||
align.o: minimap.h mmpriv.h bseq.h ksw2.h kalloc.h
|
align.o: minimap.h mmpriv.h bseq.h kseq.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
|
esterr.o: mmpriv.h minimap.h bseq.h kseq.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 kseq.h
|
||||||
hit.o: mmpriv.h minimap.h bseq.h kalloc.h khash.h
|
hit.o: mmpriv.h minimap.h bseq.h kseq.h kalloc.h khash.h
|
||||||
index.o: kthread.h bseq.h minimap.h mmpriv.h kvec.h kalloc.h khash.h
|
index.o: kthread.h bseq.h minimap.h mmpriv.h kseq.h kvec.h kalloc.h khash.h
|
||||||
|
index.o: ksort.h
|
||||||
kalloc.o: kalloc.h
|
kalloc.o: kalloc.h
|
||||||
ksw2_extd2_sse.o: ksw2.h kalloc.h
|
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
|
kthread.o: kthread.h
|
||||||
main.o: bseq.h minimap.h mmpriv.h ketopt.h
|
lchain.o: mmpriv.h minimap.h bseq.h kseq.h kalloc.h krmq.h
|
||||||
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h khash.h
|
main.o: bseq.h minimap.h mmpriv.h kseq.h ketopt.h
|
||||||
map.o: ksort.h
|
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h kseq.h
|
||||||
misc.o: mmpriv.h minimap.h bseq.h ksort.h
|
map.o: khash.h ksort.h
|
||||||
options.o: mmpriv.h minimap.h bseq.h
|
misc.o: mmpriv.h minimap.h bseq.h kseq.h ksort.h
|
||||||
pe.o: mmpriv.h minimap.h bseq.h kvec.h kalloc.h ksort.h
|
options.o: mmpriv.h minimap.h bseq.h kseq.h
|
||||||
sdust.o: kalloc.h kdq.h kvec.h ketopt.h sdust.h
|
pe.o: mmpriv.h minimap.h bseq.h kseq.h kvec.h kalloc.h ksort.h
|
||||||
sketch.o: kvec.h kalloc.h mmpriv.h minimap.h bseq.h
|
sdust.o: kalloc.h kdq.h kvec.h sdust.h
|
||||||
splitidx.o: mmpriv.h minimap.h bseq.h
|
seed.o: mmpriv.h minimap.h bseq.h kseq.h kalloc.h ksort.h
|
||||||
|
sketch.o: kvec.h kalloc.h mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
splitidx.o: mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra
|
||||||
|
CPPFLAGS= -DHAVE_KALLOC -DUSE_SIMDE -DSIMDE_ENABLE_NATIVE_ALIASES
|
||||||
|
INCLUDES= -Ilib/simde
|
||||||
|
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o options.o index.o lchain.o align.o hit.o map.o format.o pe.o seed.o esterr.o splitidx.o \
|
||||||
|
ksw2_extz2_simde.o ksw2_extd2_simde.o ksw2_exts2_simde.o ksw2_ll_simde.o
|
||||||
|
PROG= minimap2
|
||||||
|
PROG_EXTRA= sdust minimap2-lite
|
||||||
|
LIBS= -lm -lz -lpthread
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(arm_neon),) # if arm_neon is defined
|
||||||
|
ifeq ($(aarch64),) #if aarch64 is not defined
|
||||||
|
CFLAGS+=-D_FILE_OFFSET_BITS=64 -mfpu=neon -fsigned-char
|
||||||
|
else #if aarch64 is defined
|
||||||
|
CFLAGS+=-D_FILE_OFFSET_BITS=64 -fsigned-char
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(asan),)
|
||||||
|
CFLAGS+=-fsanitize=address
|
||||||
|
LIBS+=-fsanitize=address
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(tsan),)
|
||||||
|
CFLAGS+=-fsanitize=thread
|
||||||
|
LIBS+=-fsanitize=thread
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY:all extra clean depend
|
||||||
|
.SUFFIXES:.c .o
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
all:$(PROG)
|
||||||
|
|
||||||
|
extra:all $(PROG_EXTRA)
|
||||||
|
|
||||||
|
minimap2:main.o libminimap2.a
|
||||||
|
$(CC) $(CFLAGS) main.o -o $@ -L. -lminimap2 $(LIBS)
|
||||||
|
|
||||||
|
minimap2-lite:example.o libminimap2.a
|
||||||
|
$(CC) $(CFLAGS) $< -o $@ -L. -lminimap2 $(LIBS)
|
||||||
|
|
||||||
|
libminimap2.a:$(OBJS)
|
||||||
|
$(AR) -csru $@ $(OBJS)
|
||||||
|
|
||||||
|
sdust:sdust.c kalloc.o kalloc.h kdq.h kvec.h kseq.h ketopt.h sdust.h
|
||||||
|
$(CC) -D_SDUST_MAIN $(CFLAGS) $< kalloc.o -o $@ -lz
|
||||||
|
|
||||||
|
ksw2_ll_simde.o:ksw2_ll_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) -msse2 $(CPPFLAGS) $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
ksw2_extz2_simde.o:ksw2_extz2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) -msse4.1 $(CPPFLAGS) $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
ksw2_extd2_simde.o:ksw2_extd2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) -msse4.1 $(CPPFLAGS) $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
ksw2_exts2_simde.o:ksw2_exts2_sse.c ksw2.h kalloc.h
|
||||||
|
$(CC) -c $(CFLAGS) -msse4.1 $(CPPFLAGS) $(INCLUDES) $< -o $@
|
||||||
|
|
||||||
|
# other non-file targets
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -fr gmon.out *.o a.out $(PROG) $(PROG_EXTRA) *~ *.a *.dSYM build dist mappy*.so mappy.c python/mappy.c mappy.egg*
|
||||||
|
|
||||||
|
depend:
|
||||||
|
(LC_ALL=C; export LC_ALL; makedepend -Y -- $(CFLAGS) $(CPPFLAGS) -- *.c)
|
||||||
|
|
||||||
|
# DO NOT DELETE
|
||||||
|
|
||||||
|
align.o: minimap.h mmpriv.h bseq.h kseq.h ksw2.h kalloc.h
|
||||||
|
bseq.o: bseq.h kvec.h kalloc.h kseq.h
|
||||||
|
chain.o: minimap.h mmpriv.h bseq.h kseq.h kalloc.h
|
||||||
|
esterr.o: mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
example.o: minimap.h kseq.h
|
||||||
|
format.o: kalloc.h mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
hit.o: mmpriv.h minimap.h bseq.h kseq.h kalloc.h khash.h
|
||||||
|
index.o: kthread.h bseq.h minimap.h mmpriv.h kseq.h kvec.h kalloc.h khash.h
|
||||||
|
index.o: ksort.h
|
||||||
|
kalloc.o: kalloc.h
|
||||||
|
ksw2_extd2_sse.o: ksw2.h kalloc.h
|
||||||
|
ksw2_exts2_sse.o: ksw2.h kalloc.h
|
||||||
|
ksw2_extz2_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 kseq.h ketopt.h
|
||||||
|
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
map.o: khash.h ksort.h
|
||||||
|
misc.o: mmpriv.h minimap.h bseq.h kseq.h ksort.h
|
||||||
|
options.o: mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
pe.o: mmpriv.h minimap.h bseq.h kseq.h kvec.h kalloc.h ksort.h
|
||||||
|
sdust.o: kalloc.h kdq.h kvec.h sdust.h
|
||||||
|
self-chain.o: minimap.h kseq.h
|
||||||
|
sketch.o: kvec.h kalloc.h mmpriv.h minimap.h bseq.h kseq.h
|
||||||
|
splitidx.o: mmpriv.h minimap.h bseq.h kseq.h
|
||||||
@@ -1,3 +1,315 @@
|
|||||||
|
Release 2.22-r1101 (7 August 2021)
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
When choosing the best alignment, this release uses logarithm gap penalty and
|
||||||
|
query-specific mismatch penalty. It improves the sensitivity to long INDELs in
|
||||||
|
repetitive regions.
|
||||||
|
|
||||||
|
Other notable changes:
|
||||||
|
|
||||||
|
* Bugfix: fixed an indirect memory leak that may waste a large amount of
|
||||||
|
memory given highly repetitive reference such as a 16S RNA database (#749).
|
||||||
|
All versions of minimap2 have this issue.
|
||||||
|
|
||||||
|
* New feature: added --cap-kalloc to reduce the peak memory. This option is
|
||||||
|
not enabled by default but may become the default in future releases.
|
||||||
|
|
||||||
|
Known issue:
|
||||||
|
|
||||||
|
* Minimap2 may take a long time to map a read (#771). So far it is not clear
|
||||||
|
if this happens to v2.18 and earlier versions.
|
||||||
|
|
||||||
|
(2.22: 7 August 2021, r1101)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.21-r1071 (6 July 2021)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
This release fixed a regression in short-read mapping introduced in v2.19
|
||||||
|
(#776). It also fixed invalid comparisons of uninitialized variables, though
|
||||||
|
these are harmless (#752). Long-read alignment should be identical to v2.20.
|
||||||
|
|
||||||
|
(2.21: 6 July 2021, r1071)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.20-r1061 (27 May 2021)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
This release fixed a bug in the Python module and improves the command-line
|
||||||
|
compatibiliity with v2.18. In v2.19, if `-r` is specified with an `asm*` preset,
|
||||||
|
users would get alignments more fragmented than v2.18. This could be an issue
|
||||||
|
for existing pipelines specifying `-r`. This release resolves this issue.
|
||||||
|
|
||||||
|
(2.20: 27 May 2021, r1061)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.19-r1057 (26 May 2021)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
This release includes a few important improvements backported from unimap:
|
||||||
|
|
||||||
|
* Improvement: more contiguous alignment through long INDELs. This is enabled
|
||||||
|
by the minigraph chaining algorithm. All `asm*` presets now use the new
|
||||||
|
algorithm. They can find INDELs up to 100kb and may be faster for
|
||||||
|
chromosome-long contigs. The default mode and `map*` presets use this
|
||||||
|
algorithm to replace the long-join heuristic.
|
||||||
|
|
||||||
|
* Improvement: better alignment in highly repetitive regions by rescuing
|
||||||
|
high-occurrence seeds. If the distance between two adjacent seeds is too
|
||||||
|
large, attempt to choose a fraction of high-occurrence seeds in-between.
|
||||||
|
Minimap2 now produces fewer clippings and alignment break points in long
|
||||||
|
satellite regions.
|
||||||
|
|
||||||
|
* Improvement: allow to specify an interval of k-mer occurrences with `-U`.
|
||||||
|
For repeat-rich genomes, the automatic k-mer occurrence threshold determined
|
||||||
|
by `-f` may be too large and makes alignment impractically slow. The new
|
||||||
|
option protects against such cases. Enabled for `asm*` and `map-hifi`.
|
||||||
|
|
||||||
|
* New feature: added the `map-hifi` preset for maping PacBio High-Fidelity
|
||||||
|
(HiFi) reads.
|
||||||
|
|
||||||
|
* Change to the default: apply `--cap-sw-mem=100m` for genomic alignment.
|
||||||
|
|
||||||
|
* Bugfix: minimap2 could not generate an index file with `-xsr` (#734).
|
||||||
|
|
||||||
|
This release represents the most signficant algorithmic change since v2.1 in
|
||||||
|
2017. With features backported from unimap, minimap2 now has similar power to
|
||||||
|
unimap for contig alignment. Unimap will remain an experimental project and is
|
||||||
|
no longer recommended over minimap2. Sorry for reverting the recommendation in
|
||||||
|
short time.
|
||||||
|
|
||||||
|
(2.19: 26 May 2021, r1057)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.18-r1015 (9 April 2021)
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
This release fixes multiple rare bugs in minimap2 and adds additional
|
||||||
|
functionality to paftools.js.
|
||||||
|
|
||||||
|
Changes to minimap2:
|
||||||
|
|
||||||
|
* Bugfix: a rare segfault caused by an off-by-one error (#489)
|
||||||
|
|
||||||
|
* Bugfix: minimap2 segfaulted due to an uninitilized variable (#622 and #625).
|
||||||
|
|
||||||
|
* Bugfix: minimap2 parsed spaces as field separators in BED (#721). This led
|
||||||
|
to issues when the BED name column contains spaces.
|
||||||
|
|
||||||
|
* Bugfix: minimap2 `--split-prefix` did not work with long reference names
|
||||||
|
(#394).
|
||||||
|
|
||||||
|
* Bugfix: option `--junc-bonus` didn't work (#513)
|
||||||
|
|
||||||
|
* Bugfix: minimap2 didn't return 1 on I/O errors (#532)
|
||||||
|
|
||||||
|
* Bugfix: the `de:f` tag (sequence divergence) could be negative if there were
|
||||||
|
ambiguous bases
|
||||||
|
|
||||||
|
* Bugfix: fixed two undefined behaviors caused by calling memcpy() on
|
||||||
|
zero-length blocks (#443)
|
||||||
|
|
||||||
|
* Bugfix: there were duplicated SAM @SQ lines if option `--split-prefix` is in
|
||||||
|
use (#400 and #527)
|
||||||
|
|
||||||
|
* Bugfix: option -K had to be smaller than 2 billion (#491). This was caused
|
||||||
|
by a 32-bit integer overflow.
|
||||||
|
|
||||||
|
* Improvement: optionally compile against SIMDe (#597). Minimap2 should work
|
||||||
|
with IBM POWER CPUs, though this has not been tested. To compile with SIMDe,
|
||||||
|
please use `make -f Makefile.simde`.
|
||||||
|
|
||||||
|
* Improvement: more informative error message for I/O errors (#454) and for
|
||||||
|
FASTQ parsing errors (#510)
|
||||||
|
|
||||||
|
* Improvement: abort given malformatted RG line (#541)
|
||||||
|
|
||||||
|
* Improvement: better formula to estimate the `dv:f` tag (approximate sequence
|
||||||
|
divergence). See DOI:10.1101/2021.01.15.426881.
|
||||||
|
|
||||||
|
* New feature: added the `--mask-len` option to fine control the removal of
|
||||||
|
redundant hits (#659). The default behavior is unchanged.
|
||||||
|
|
||||||
|
Changes to mappy:
|
||||||
|
|
||||||
|
* Bugfix: mappy caused segmentation fault if the reference index is not
|
||||||
|
present (#413).
|
||||||
|
|
||||||
|
* Bugfix: fixed a memory leak via 238b6bb3
|
||||||
|
|
||||||
|
* Change: always require Cython to compile the mappy module (#723). Older
|
||||||
|
mappy packages at PyPI bundled the C source code generated by Cython such
|
||||||
|
that end users did not need to install Cython to compile mappy. However, as
|
||||||
|
Python 3.9 is breaking backward compatibility, older mappy does not work
|
||||||
|
with Python 3.9 anymore. We have to add this Cython dependency as a
|
||||||
|
workaround.
|
||||||
|
|
||||||
|
Changes to paftools.js:
|
||||||
|
|
||||||
|
* Bugfix: the "part10-" line from asmgene was wrong (#581)
|
||||||
|
|
||||||
|
* Improvement: compatibility with GTF files from GenBank (#422)
|
||||||
|
|
||||||
|
* New feature: asmgene also checks missing multi-copy genes
|
||||||
|
|
||||||
|
* New feature: added the misjoin command to evaluate large-scale misjoins and
|
||||||
|
megabase-long inversions.
|
||||||
|
|
||||||
|
Although given the many bug fixes and minor improvements, the core algorithm
|
||||||
|
stays the same. This version of minimap2 produces nearly identical alignments
|
||||||
|
to v2.17 except very rare corner cases.
|
||||||
|
|
||||||
|
Now unimap is recommended over minimap2 for aligning long contigs against a
|
||||||
|
reference genome. It often takes less wall-clock time and is much more
|
||||||
|
sensitive to long insertions and deletions.
|
||||||
|
|
||||||
|
(2.18: 9 April 2021, r1015)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.17-r941 (4 May 2019)
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
Changes since the last release:
|
||||||
|
|
||||||
|
* Fixed flawed CIGARs like `5I6D7I` (#392).
|
||||||
|
|
||||||
|
* Bugfix: TLEN should be 0 when either end is unmapped (#373 and #365).
|
||||||
|
|
||||||
|
* Bugfix: mappy is unable to write index (#372).
|
||||||
|
|
||||||
|
* Added option `--junc-bed` to load known gene annotations in the BED12
|
||||||
|
format. Minimap2 prefers annotated junctions over novel junctions (#197 and
|
||||||
|
#348). GTF can be converted to BED12 with `paftools.js gff2bed`.
|
||||||
|
|
||||||
|
* Added option `--sam-hit-only` to suppress unmapped hits in SAM (#377).
|
||||||
|
|
||||||
|
* Added preset `splice:hq` for high-quality CCS or mRNA sequences. It applies
|
||||||
|
better scoring and improves the sensitivity to small exons. This preset may
|
||||||
|
introduce false small introns, but the overall accuracy should be higher.
|
||||||
|
|
||||||
|
This version produces nearly identical alignments to v2.16, except for CIGARs
|
||||||
|
affected by the bug mentioned above.
|
||||||
|
|
||||||
|
(2.17: 5 May 2019, r941)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.16-r922 (28 February 2019)
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
This release is 50% faster for mapping ultra-long nanopore reads at comparable
|
||||||
|
accuracy. For short-read mapping, long-read overlapping and ordinary long-read
|
||||||
|
mapping, the performance and accuracy remain similar. This speedup is achieved
|
||||||
|
with a new heuristic to limit the number of chaining iterations (#324). Users
|
||||||
|
can disable the heuristic by increasing a new option `--max-chain-iter` to a
|
||||||
|
huge number.
|
||||||
|
|
||||||
|
Other changes to minimap2:
|
||||||
|
|
||||||
|
* Implemented option `--paf-no-hit` to output unmapped query sequences in PAF.
|
||||||
|
The strand and reference name columns are both `*` at an unmapped line. The
|
||||||
|
hidden option is available in earlier minimap2 but had a different 2-column
|
||||||
|
output format instead of PAF.
|
||||||
|
|
||||||
|
* Fixed a bug that leads to wrongly calculated `de` tags when ambiguous bases
|
||||||
|
are involved (#309). This bug only affects v2.15.
|
||||||
|
|
||||||
|
* Fixed a bug when parsing command-line option `--splice` (#344). This bug was
|
||||||
|
introduced in v2.13.
|
||||||
|
|
||||||
|
* Fixed two division-by-zero cases (#326). They don't affect final alignments
|
||||||
|
because the results of the divisions are not used in both case.
|
||||||
|
|
||||||
|
* Added an option `-o` to output alignments to a specified file. It is still
|
||||||
|
recommended to use UNIX pipes for on-the-fly conversion or compression.
|
||||||
|
|
||||||
|
* Output a new `rl` tag to give the length of query regions harboring
|
||||||
|
repetitive seeds.
|
||||||
|
|
||||||
|
Changes to paftool.js:
|
||||||
|
|
||||||
|
* Added a new option to convert the MD tag to the long form of the cs tag.
|
||||||
|
|
||||||
|
Changes to mappy:
|
||||||
|
|
||||||
|
* Added the `mappy.Aligner.seq_names` method to return sequence names (#312).
|
||||||
|
|
||||||
|
For NA12878 ultra-long reads, this release changes the alignments of <0.1% of
|
||||||
|
reads in comparison to v2.15. All these reads have highly fragmented alignments
|
||||||
|
and are likely to be problematic anyway. For shorter or well aligned reads,
|
||||||
|
this release should produce mostly identical alignments to v2.15.
|
||||||
|
|
||||||
|
(2.16: 28 February 2019, r922)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.15-r905 (10 January 2019)
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Changes to minimap2:
|
||||||
|
|
||||||
|
* Fixed a rare segmentation fault when option -H is in use (#307). This may
|
||||||
|
happen when there are very long homopolymers towards the 5'-end of a read.
|
||||||
|
|
||||||
|
* Fixed wrong CIGARs when option --eqx is used (#266).
|
||||||
|
|
||||||
|
* Fixed a typo in the base encoding table (#264). This should have no
|
||||||
|
practical effect.
|
||||||
|
|
||||||
|
* Fixed a typo in the example code (#265).
|
||||||
|
|
||||||
|
* Improved the C++ compatibility by removing "register" (#261). However,
|
||||||
|
minimap2 still can't be compiled in the pedantic C++ mode (#306).
|
||||||
|
|
||||||
|
* Output a new "de" tag for gap-compressed sequence divergence.
|
||||||
|
|
||||||
|
Changes to paftools.js:
|
||||||
|
|
||||||
|
* Added "asmgene" to evaluate the completeness of an assembly by measuring the
|
||||||
|
uniquely mapped single-copy genes. This command learns the idea of BUSCO.
|
||||||
|
|
||||||
|
* Added "vcfpair" to call a phased VCF from phased whole-genome assemblies. An
|
||||||
|
earlier version of this script is used to produce the ground truth for the
|
||||||
|
syndip benchmark [PMID:30013044].
|
||||||
|
|
||||||
|
This release produces identical alignment coordinates and CIGARs in comparison
|
||||||
|
to v2.14. Users are advised to upgrade due to the several bug fixes.
|
||||||
|
|
||||||
|
(2.15: 10 Janurary 2019, r905)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Release 2.14-r883 (5 November 2018)
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Notable changes:
|
||||||
|
|
||||||
|
* Fixed two minor bugs caused by typos (#254 and #266).
|
||||||
|
|
||||||
|
* Fixed a bug that made minimap2 abort when --eqx was used together with --MD
|
||||||
|
or --cs (#257).
|
||||||
|
|
||||||
|
* Added --cap-sw-mem to cap the size of DP matrices (#259). Base alignment may
|
||||||
|
take a lot of memory in the splicing mode. This may lead to issues when we
|
||||||
|
run minimap2 on a cluster with a hard memory limit. The new option avoids
|
||||||
|
unlimited memory usage at the cost of missing a few long introns.
|
||||||
|
|
||||||
|
* Conforming to C99 and C11 when possible (#261).
|
||||||
|
|
||||||
|
* Warn about malformatted FASTA or FASTQ (#252 and #255).
|
||||||
|
|
||||||
|
This release occasionally produces base alignments different from v2.13. The
|
||||||
|
overall alignment accuracy remain similar.
|
||||||
|
|
||||||
|
(2.14: 5 November 2018, r883)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Release 2.13-r850 (11 October 2018)
|
Release 2.13-r850 (11 October 2018)
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[](https://github.com/lh3/minimap2/releases)
|
[](https://github.com/lh3/minimap2/releases)
|
||||||
[](https://anaconda.org/bioconda/minimap2)
|
[](https://anaconda.org/bioconda/minimap2)
|
||||||
[](https://pypi.python.org/pypi/mappy)
|
[](https://pypi.python.org/pypi/mappy)
|
||||||
[](https://travis-ci.org/lh3/minimap2)
|
[](https://github.com/lh3/minimap2/actions)
|
||||||
## <a name="started"></a>Getting Started
|
## <a name="started"></a>Getting Started
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/lh3/minimap2
|
git clone https://github.com/lh3/minimap2
|
||||||
@@ -9,22 +9,25 @@ cd minimap2 && make
|
|||||||
# long sequences against a reference genome
|
# long sequences against a reference genome
|
||||||
./minimap2 -a test/MT-human.fa test/MT-orang.fa > test.sam
|
./minimap2 -a test/MT-human.fa test/MT-orang.fa > test.sam
|
||||||
# create an index first and then map
|
# create an index first and then map
|
||||||
./minimap2 -d MT-human.mmi test/MT-human.fa
|
./minimap2 -x map-ont -d MT-human-ont.mmi test/MT-human.fa
|
||||||
./minimap2 -a MT-human.mmi test/MT-orang.fa > test.sam
|
./minimap2 -a MT-human-ont.mmi test/MT-orang.fa > test.sam
|
||||||
# use presets (no test data)
|
# use presets (no test data)
|
||||||
./minimap2 -ax map-pb ref.fa pacbio.fq.gz > aln.sam # PacBio genomic reads
|
./minimap2 -ax map-pb ref.fa pacbio.fq.gz > aln.sam # PacBio CLR genomic reads
|
||||||
./minimap2 -ax map-ont ref.fa ont.fq.gz > aln.sam # Oxford Nanopore genomic reads
|
./minimap2 -ax map-ont ref.fa ont.fq.gz > aln.sam # Oxford Nanopore genomic reads
|
||||||
./minimap2 -ax asm20 ref.fa pacbio-ccs.fq.gz > aln.sam # PacBio CCS genomic reads
|
./minimap2 -ax map-hifi ref.fa pacbio-ccs.fq.gz > aln.sam # PacBio HiFi/CCS genomic reads (v2.19 or later)
|
||||||
|
./minimap2 -ax asm20 ref.fa pacbio-ccs.fq.gz > aln.sam # PacBio HiFi/CCS genomic reads (v2.18 or earlier)
|
||||||
./minimap2 -ax sr ref.fa read1.fa read2.fa > aln.sam # short genomic paired-end reads
|
./minimap2 -ax sr ref.fa read1.fa read2.fa > aln.sam # short genomic paired-end reads
|
||||||
./minimap2 -ax splice ref.fa rna-reads.fa > aln.sam # spliced long reads (strand unknown)
|
./minimap2 -ax splice ref.fa rna-reads.fa > aln.sam # spliced long reads (strand unknown)
|
||||||
./minimap2 -ax splice -uf -k14 ref.fa reads.fa > aln.sam # noisy Nanopore Direct RNA-seq
|
./minimap2 -ax splice -uf -k14 ref.fa reads.fa > aln.sam # noisy Nanopore Direct RNA-seq
|
||||||
./minimap2 -ax splice -uf -C5 ref.fa query.fa > aln.sam # Final PacBio Iso-seq or traditional cDNA
|
./minimap2 -ax splice:hq -uf ref.fa query.fa > aln.sam # Final PacBio Iso-seq or traditional cDNA
|
||||||
|
./minimap2 -ax splice --junc-bed anno.bed12 ref.fa query.fa > aln.sam # prioritize on annotated junctions
|
||||||
./minimap2 -cx asm5 asm1.fa asm2.fa > aln.paf # intra-species asm-to-asm alignment
|
./minimap2 -cx asm5 asm1.fa asm2.fa > aln.paf # intra-species asm-to-asm alignment
|
||||||
./minimap2 -x ava-pb reads.fa reads.fa > overlaps.paf # PacBio read overlap
|
./minimap2 -x ava-pb reads.fa reads.fa > overlaps.paf # PacBio read overlap
|
||||||
./minimap2 -x ava-ont reads.fa reads.fa > overlaps.paf # Nanopore read overlap
|
./minimap2 -x ava-ont reads.fa reads.fa > overlaps.paf # Nanopore read overlap
|
||||||
# man page for detailed command line options
|
# man page for detailed command line options
|
||||||
man ./minimap2.1
|
man ./minimap2.1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Getting Started](#started)
|
- [Getting Started](#started)
|
||||||
@@ -71,8 +74,8 @@ Detailed evaluations are available from the [minimap2 paper][doi] or the
|
|||||||
Minimap2 is optimized for x86-64 CPUs. You can acquire precompiled binaries from
|
Minimap2 is optimized for x86-64 CPUs. You can acquire precompiled binaries from
|
||||||
the [release page][release] with:
|
the [release page][release] with:
|
||||||
```sh
|
```sh
|
||||||
curl -L https://github.com/lh3/minimap2/releases/download/v2.13/minimap2-2.13_x64-linux.tar.bz2 | tar -jxvf -
|
curl -L https://github.com/lh3/minimap2/releases/download/v2.22/minimap2-2.22_x64-linux.tar.bz2 | tar -jxvf -
|
||||||
./minimap2-2.13_x64-linux/minimap2
|
./minimap2-2.22_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
|
||||||
@@ -80,13 +83,20 @@ 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
|
Minimap2 also works with ARM CPUs supporting the NEON instruction sets. To
|
||||||
compile for 32 bit ARM architectures (such as ARMv7), use `make arm_neon=1`. To compile for for 64 bit ARM architectures (such as ARMv8), use `make arm_neon=1 aarch64=1`.
|
compile for 32 bit ARM architectures (such as ARMv7), use `make arm_neon=1`. To
|
||||||
|
compile for for 64 bit ARM architectures (such as ARMv8), use `make arm_neon=1
|
||||||
|
aarch64=1`.
|
||||||
|
|
||||||
|
Minimap2 can use [SIMD Everywhere (SIMDe)][simde] library for porting
|
||||||
|
implementation to the different SIMD instruction sets. To compile using SIMDe,
|
||||||
|
use `make -f Makefile.simde`. To compile for ARM CPUs, use `Makefile.simde`
|
||||||
|
with the ARM related command lines given above.
|
||||||
|
|
||||||
### <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
|
||||||
file as input and produce approximate mapping, without base-level alignment
|
file as input and produce approximate mapping, without base-level alignment
|
||||||
(i.e. no CIGAR), in the [PAF format][paf]:
|
(i.e. coordinates are only approximate and no CIGAR in output), in the [PAF format][paf]:
|
||||||
```sh
|
```sh
|
||||||
minimap2 ref.fa query.fq > approx-mapping.paf
|
minimap2 ref.fa query.fq > approx-mapping.paf
|
||||||
```
|
```
|
||||||
@@ -127,19 +137,19 @@ parameters at the same time. The default setting is the same as `map-ont`.
|
|||||||
#### <a name="map-long-genomic"></a>Map long noisy genomic reads
|
#### <a name="map-long-genomic"></a>Map long noisy genomic reads
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
minimap2 -ax map-pb ref.fa pacbio-reads.fq > aln.sam # for PacBio subreads
|
minimap2 -ax map-pb ref.fa pacbio-reads.fq > aln.sam # for PacBio CLR reads
|
||||||
minimap2 -ax map-ont ref.fa ont-reads.fq > aln.sam # for Oxford Nanopore reads
|
minimap2 -ax map-ont ref.fa ont-reads.fq > aln.sam # for Oxford Nanopore reads
|
||||||
```
|
```
|
||||||
The difference between `map-pb` and `map-ont` is that `map-pb` uses
|
The difference between `map-pb` and `map-ont` is that `map-pb` uses
|
||||||
homopolymer-compressed (HPC) minimizers as seeds, while `map-ont` uses ordinary
|
homopolymer-compressed (HPC) minimizers as seeds, while `map-ont` uses ordinary
|
||||||
minimizers as seeds. Emperical evaluation suggests HPC minimizers improve
|
minimizers as seeds. Emperical evaluation suggests HPC minimizers improve
|
||||||
performance and sensitivity when aligning PacBio reads, but hurt when aligning
|
performance and sensitivity when aligning PacBio CLR reads, but hurt when aligning
|
||||||
Nanopore reads.
|
Nanopore reads.
|
||||||
|
|
||||||
#### <a name="map-long-splice"></a>Map long mRNA/cDNA reads
|
#### <a name="map-long-splice"></a>Map long mRNA/cDNA reads
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
minimap2 -ax splice -uf -C5 ref.fa iso-seq.fq > aln.sam # PacBio Iso-seq/traditional cDNA
|
minimap2 -ax splice:hq -uf ref.fa iso-seq.fq > aln.sam # PacBio Iso-seq/traditional cDNA
|
||||||
minimap2 -ax splice ref.fa nanopore-cdna.fa > aln.sam # Nanopore 2D cDNA-seq
|
minimap2 -ax splice ref.fa nanopore-cdna.fa > aln.sam # Nanopore 2D cDNA-seq
|
||||||
minimap2 -ax splice -uf -k14 ref.fa direct-rna.fq > aln.sam # Nanopore Direct RNA-seq
|
minimap2 -ax splice -uf -k14 ref.fa direct-rna.fq > aln.sam # Nanopore Direct RNA-seq
|
||||||
minimap2 -ax splice --splice-flank=no SIRV.fa SIRV-seq.fa # mapping against SIRV control
|
minimap2 -ax splice --splice-flank=no SIRV.fa SIRV-seq.fa # mapping against SIRV control
|
||||||
@@ -178,10 +188,23 @@ This is because SIRV does not honor the evolutionarily conservative splicing
|
|||||||
signal. If you are studying SIRV, you may apply `--splice-flank=no` to let
|
signal. If you are studying SIRV, you may apply `--splice-flank=no` to let
|
||||||
minimap2 only model GT..AG, ignoring the additional base.
|
minimap2 only model GT..AG, ignoring the additional base.
|
||||||
|
|
||||||
|
Since v2.17, minimap2 can optionally take annotated genes as input and
|
||||||
|
prioritize on annotated splice junctions. To use this feature, you can
|
||||||
|
```sh
|
||||||
|
paftools.js gff2bed anno.gff > anno.bed
|
||||||
|
minimap2 -ax splice --junc-bed anno.bed ref.fa query.fa > aln.sam
|
||||||
|
```
|
||||||
|
Here, `anno.gff` is the gene annotation in the GTF or GFF3 format (`gff2bed`
|
||||||
|
automatically tests the format). The output of `gff2bed` is in the 12-column
|
||||||
|
BED format, or the BED12 format. With the `--junc-bed` option, minimap2 adds a
|
||||||
|
bonus score (tuned by `--junc-bonus`) if an aligned junction matches a junction
|
||||||
|
in the annotation. Option `--junc-bed` also takes 5-column BED, including the
|
||||||
|
strand field. In this case, each line indicates an oriented junction.
|
||||||
|
|
||||||
#### <a name="long-overlap"></a>Find overlaps between long reads
|
#### <a name="long-overlap"></a>Find overlaps between long reads
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
minimap2 -x ava-pb reads.fq reads.fq > ovlp.paf # PacBio read overlap
|
minimap2 -x ava-pb reads.fq reads.fq > ovlp.paf # PacBio CLR read overlap
|
||||||
minimap2 -x ava-ont reads.fq reads.fq > ovlp.paf # Oxford Nanopore read overlap
|
minimap2 -x ava-ont reads.fq reads.fq > ovlp.paf # Oxford Nanopore read overlap
|
||||||
```
|
```
|
||||||
Similarly, `ava-pb` uses HPC minimizers while `ava-ont` uses ordinary
|
Similarly, `ava-pb` uses HPC minimizers while `ava-ont` uses ordinary
|
||||||
@@ -228,7 +251,7 @@ To avoid this issue, you can add option `-L` at the minimap2 command line.
|
|||||||
This option moves a long CIGAR to the `CG` tag and leaves a fully clipped CIGAR
|
This option moves a long CIGAR to the `CG` tag and leaves a fully clipped CIGAR
|
||||||
at the SAM CIGAR column. Current tools that don't read CIGAR (e.g. merging and
|
at the SAM CIGAR column. Current tools that don't read CIGAR (e.g. merging and
|
||||||
sorting) still work with such BAM records; tools that read CIGAR will
|
sorting) still work with such BAM records; tools that read CIGAR will
|
||||||
effectively ignore these records. It has been decided that future tools will
|
effectively ignore these records. It has been decided that future tools
|
||||||
will seamlessly recognize long-cigar records generated by option `-L`.
|
will seamlessly recognize long-cigar records generated by option `-L`.
|
||||||
|
|
||||||
**TL;DR**: if you work with ultra-long reads and use tools that only process
|
**TL;DR**: if you work with ultra-long reads and use tools that only process
|
||||||
@@ -249,7 +272,7 @@ CGATCGATAAATAGAGTAG---GAATAGCA
|
|||||||
CGATCG---AATAGAGTAGGTCGAATtGCA
|
CGATCG---AATAGAGTAGGTCGAATtGCA
|
||||||
```
|
```
|
||||||
is represented as `:6-ata:10+gtc:4*at:3`, where `:[0-9]+` represents an
|
is represented as `:6-ata:10+gtc:4*at:3`, where `:[0-9]+` represents an
|
||||||
identical block, `-ata` represents a deltion, `+gtc` an insertion and `*at`
|
identical block, `-ata` represents a deletion, `+gtc` an insertion and `*at`
|
||||||
indicates reference base `a` is substituted with a query base `t`. It is
|
indicates reference base `a` is substituted with a query base `t`. It is
|
||||||
similar to the `MD` SAM tag but is standalone and easier to parse.
|
similar to the `MD` SAM tag but is standalone and easier to parse.
|
||||||
|
|
||||||
@@ -315,16 +338,17 @@ highlighted in bold. The description may help to tune minimap2 parameters.
|
|||||||
### <a name="help"></a>Getting help
|
### <a name="help"></a>Getting help
|
||||||
|
|
||||||
Manpage [minimap2.1][manpage] provides detailed description of minimap2
|
Manpage [minimap2.1][manpage] provides detailed description of minimap2
|
||||||
command line options and optional tags. If you encounter bugs or have further
|
command line options and optional tags. The [FAQ](FAQ.md) page answers several
|
||||||
questions or requests, you can raise an issue at the [issue page][issue].
|
frequently asked questions. If you encounter bugs or have further questions or
|
||||||
There is not a specific mailing list for the time being.
|
requests, you can raise an issue at the [issue page][issue]. There is not a
|
||||||
|
specific mailing list for the time being.
|
||||||
|
|
||||||
### <a name="cite"></a>Citing minimap2
|
### <a name="cite"></a>Citing minimap2
|
||||||
|
|
||||||
If you use minimap2 in your work, please cite:
|
If you use minimap2 in your work, please cite:
|
||||||
|
|
||||||
> Li, H. (2018). Minimap2: pairwise alignment for nucleotide sequences.
|
> Li, H. (2018). Minimap2: pairwise alignment for nucleotide sequences.
|
||||||
> Bioinformatics. [doi:10.1093/bioinformatics/bty191][doi]
|
> *Bioinformatics*, **34**:3094-3100. [doi:10.1093/bioinformatics/bty191][doi]
|
||||||
|
|
||||||
## <a name="dguide"></a>Developers' Guide
|
## <a name="dguide"></a>Developers' Guide
|
||||||
|
|
||||||
@@ -355,6 +379,8 @@ mappy` or [from BioConda][mappyconda] via `conda install -c bioconda mappy`.
|
|||||||
billion bases or longer (2,147,483,647 to be exact). The total length of all
|
billion bases or longer (2,147,483,647 to be exact). The total length of all
|
||||||
sequences can well exceed this threshold.
|
sequences can well exceed this threshold.
|
||||||
|
|
||||||
|
* Minimap2 often misses small exons.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
|
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
|
||||||
@@ -373,3 +399,5 @@ mappy` or [from BioConda][mappyconda] via `conda install -c bioconda mappy`.
|
|||||||
[manpage]: https://lh3.github.io/minimap2/minimap2.html
|
[manpage]: https://lh3.github.io/minimap2/minimap2.html
|
||||||
[manpage-cs]: https://lh3.github.io/minimap2/minimap2.html#10
|
[manpage-cs]: https://lh3.github.io/minimap2/minimap2.html#10
|
||||||
[doi]: https://doi.org/10.1093/bioinformatics/bty191
|
[doi]: https://doi.org/10.1093/bioinformatics/bty191
|
||||||
|
[smide]: https://github.com/nemequ/simde
|
||||||
|
[unimap]: https://github.com/lh3/unimap
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ static inline void update_max_zdrop(int32_t score, int i, int j, int32_t *max, i
|
|||||||
int z = *max - score - diff * e;
|
int z = *max - score - diff * e;
|
||||||
if (z > *max_zdrop) {
|
if (z > *max_zdrop) {
|
||||||
*max_zdrop = z;
|
*max_zdrop = z;
|
||||||
pos[0][0] = *max_i, pos[0][1] = i + 1;
|
pos[0][0] = *max_i, pos[0][1] = i;
|
||||||
pos[1][0] = *max_j, pos[1][1] = j + 1;
|
pos[1][0] = *max_j, pos[1][1] = j;
|
||||||
}
|
}
|
||||||
} else *max = score, *max_i = i, *max_j = j;
|
} else *max = score, *max_i = i, *max_j = j;
|
||||||
}
|
}
|
||||||
@@ -53,16 +53,16 @@ static int mm_test_zdrop(void *km, const mm_mapopt_t *opt, const uint8_t *qseq,
|
|||||||
// find the score and the region where score drops most along diagonal
|
// find the score and the region where score drops most along diagonal
|
||||||
for (k = 0, score = 0; k < n_cigar; ++k) {
|
for (k = 0, score = 0; k < n_cigar; ++k) {
|
||||||
uint32_t l, op = cigar[k]&0xf, len = cigar[k]>>4;
|
uint32_t l, op = cigar[k]&0xf, len = cigar[k]>>4;
|
||||||
if (op == 0) {
|
if (op == MM_CIGAR_MATCH) {
|
||||||
for (l = 0; l < len; ++l) {
|
for (l = 0; l < len; ++l) {
|
||||||
score += mat[tseq[i + l] * 5 + qseq[j + l]];
|
score += mat[tseq[i + l] * 5 + qseq[j + l]];
|
||||||
update_max_zdrop(score, i+l, j+l, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
update_max_zdrop(score, i+l, j+l, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
||||||
}
|
}
|
||||||
i += len, j += len;
|
i += len, j += len;
|
||||||
} else if (op == 1 || op == 2 || op == 3) {
|
} else if (op == MM_CIGAR_INS || op == MM_CIGAR_DEL || op == MM_CIGAR_N_SKIP) {
|
||||||
score -= opt->q + opt->e * len;
|
score -= opt->q + opt->e * len;
|
||||||
if (op == 1) j += len; // insertion
|
if (op == MM_CIGAR_INS) j += len;
|
||||||
else i += len; // deletion
|
else i += len;
|
||||||
update_max_zdrop(score, i, j, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
update_max_zdrop(score, i, j, &max, &max_i, &max_j, opt->e, &max_zdrop, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,23 +88,22 @@ static int mm_test_zdrop(void *km, const mm_mapopt_t *opt, const uint8_t *qseq,
|
|||||||
return max_zdrop > opt->zdrop? 1 : 0;
|
return max_zdrop > opt->zdrop? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq, int *qshift, int *tshift, int left_aln)
|
static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq, int *qshift, int *tshift)
|
||||||
{
|
{
|
||||||
mm_extra_t *p = r->p;
|
mm_extra_t *p = r->p;
|
||||||
int32_t toff = 0, qoff = 0, to_shrink = 0;
|
int32_t toff = 0, qoff = 0, to_shrink = 0;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
*qshift = *tshift = 0;
|
*qshift = *tshift = 0;
|
||||||
if (p->n_cigar <= 1) return;
|
if (p->n_cigar <= 1) return;
|
||||||
if (!left_aln) goto end_left_aln;
|
|
||||||
for (k = 0; k < p->n_cigar; ++k) { // indel left alignment
|
for (k = 0; k < p->n_cigar; ++k) { // indel left alignment
|
||||||
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
||||||
if (len == 0) to_shrink = 1;
|
if (len == 0) to_shrink = 1;
|
||||||
if (op == 0) {
|
if (op == MM_CIGAR_MATCH) {
|
||||||
toff += len, qoff += len;
|
toff += len, qoff += len;
|
||||||
} else if (op == 1 || op == 2) { // insertion or deletion
|
} else if (op == MM_CIGAR_INS || op == MM_CIGAR_DEL) {
|
||||||
if (k > 0 && k < p->n_cigar - 1 && (p->cigar[k-1]&0xf) == 0 && (p->cigar[k+1]&0xf) == 0) {
|
if (k > 0 && k < p->n_cigar - 1 && (p->cigar[k-1]&0xf) == 0 && (p->cigar[k+1]&0xf) == 0) {
|
||||||
int l, prev_len = p->cigar[k-1] >> 4;
|
int l, prev_len = p->cigar[k-1] >> 4;
|
||||||
if (op == 1) {
|
if (op == MM_CIGAR_INS) {
|
||||||
for (l = 0; l < prev_len; ++l)
|
for (l = 0; l < prev_len; ++l)
|
||||||
if (qseq[qoff - 1 - l] != qseq[qoff + len - 1 - l])
|
if (qseq[qoff - 1 - l] != qseq[qoff + len - 1 - l])
|
||||||
break;
|
break;
|
||||||
@@ -117,14 +116,32 @@ static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq,
|
|||||||
p->cigar[k-1] -= l<<4, p->cigar[k+1] += l<<4, qoff -= l, toff -= l;
|
p->cigar[k-1] -= l<<4, p->cigar[k+1] += l<<4, qoff -= l, toff -= l;
|
||||||
if (l == prev_len) to_shrink = 1;
|
if (l == prev_len) to_shrink = 1;
|
||||||
}
|
}
|
||||||
if (op == 1) qoff += len;
|
if (op == MM_CIGAR_INS) qoff += len;
|
||||||
else toff += len;
|
else toff += len;
|
||||||
} else if (op == 3) {
|
} else if (op == MM_CIGAR_N_SKIP) {
|
||||||
toff += len;
|
toff += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
|
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
|
||||||
end_left_aln:
|
for (k = 0; k < p->n_cigar - 2; ++k) { // fix CIGAR like 5I6D7I
|
||||||
|
if ((p->cigar[k]&0xf) > 0 && (p->cigar[k]&0xf) + (p->cigar[k+1]&0xf) == 3) {
|
||||||
|
uint32_t l, s[3] = {0,0,0};
|
||||||
|
for (l = k; l < p->n_cigar; ++l) { // count number of adjacent I and D
|
||||||
|
uint32_t op = p->cigar[l]&0xf;
|
||||||
|
if (op == MM_CIGAR_INS || op == MM_CIGAR_DEL || p->cigar[l]>>4 == 0)
|
||||||
|
s[op] += p->cigar[l] >> 4;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
if (s[1] > 0 && s[2] > 0 && l - k > 2) { // turn to a single I and a single D
|
||||||
|
p->cigar[k] = s[1]<<4|MM_CIGAR_INS;
|
||||||
|
p->cigar[k+1] = s[2]<<4|MM_CIGAR_DEL;
|
||||||
|
for (k += 2; k < l; ++k)
|
||||||
|
p->cigar[k] &= 0xf;
|
||||||
|
to_shrink = 1;
|
||||||
|
}
|
||||||
|
k = l;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (to_shrink) { // squeeze out zero-length operations
|
if (to_shrink) { // squeeze out zero-length operations
|
||||||
int32_t l = 0;
|
int32_t l = 0;
|
||||||
for (k = 0; k < p->n_cigar; ++k) // squeeze out zero-length operations
|
for (k = 0; k < p->n_cigar; ++k) // squeeze out zero-length operations
|
||||||
@@ -137,9 +154,9 @@ end_left_aln:
|
|||||||
else p->cigar[k+1] += p->cigar[k]>>4<<4; // add length to the next CIGAR operator
|
else p->cigar[k+1] += p->cigar[k]>>4<<4; // add length to the next CIGAR operator
|
||||||
p->n_cigar = l;
|
p->n_cigar = l;
|
||||||
}
|
}
|
||||||
if ((p->cigar[0]&0xf) == 1 || (p->cigar[0]&0xf) == 2) { // get rid of leading I or D
|
if ((p->cigar[0]&0xf) == MM_CIGAR_INS || (p->cigar[0]&0xf) == MM_CIGAR_DEL) { // get rid of leading I or D
|
||||||
int32_t l = p->cigar[0] >> 4;
|
int32_t l = p->cigar[0] >> 4;
|
||||||
if ((p->cigar[0]&0xf) == 1) {
|
if ((p->cigar[0]&0xf) == MM_CIGAR_INS) {
|
||||||
if (r->rev) r->qe -= l;
|
if (r->rev) r->qe -= l;
|
||||||
else r->qs += l;
|
else r->qs += l;
|
||||||
*qshift = l;
|
*qshift = l;
|
||||||
@@ -149,18 +166,90 @@ end_left_aln:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mm_update_extra(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq, const int8_t *mat, int8_t q, int8_t e, int left_aln)
|
static void mm_update_cigar_eqx(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq) // written by @armintoepfer
|
||||||
|
{
|
||||||
|
uint32_t n_EQX = 0;
|
||||||
|
uint32_t k, l, m, cap, toff = 0, qoff = 0, n_M = 0;
|
||||||
|
mm_extra_t *p;
|
||||||
|
if (r->p == 0) return;
|
||||||
|
for (k = 0; k < r->p->n_cigar; ++k) {
|
||||||
|
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
||||||
|
if (op == MM_CIGAR_MATCH) {
|
||||||
|
while (len > 0) {
|
||||||
|
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l]; ++l) {} // run of "="; TODO: N<=>N is converted to "="
|
||||||
|
if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
|
||||||
|
|
||||||
|
for (l = 0; l < len && qseq[qoff + l] != tseq[toff + l]; ++l) {} // run of "X"
|
||||||
|
if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
|
||||||
|
}
|
||||||
|
++n_M;
|
||||||
|
} else if (op == MM_CIGAR_INS) {
|
||||||
|
qoff += len;
|
||||||
|
} else if (op == MM_CIGAR_DEL) {
|
||||||
|
toff += len;
|
||||||
|
} else if (op == MM_CIGAR_N_SKIP) {
|
||||||
|
toff += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update in-place if we can
|
||||||
|
if (n_EQX == n_M) {
|
||||||
|
for (k = 0; k < r->p->n_cigar; ++k) {
|
||||||
|
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
||||||
|
if (op == MM_CIGAR_MATCH) r->p->cigar[k] = len << 4 | MM_CIGAR_EQ_MATCH;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// allocate new storage
|
||||||
|
cap = r->p->n_cigar + (n_EQX - n_M) + sizeof(mm_extra_t);
|
||||||
|
kroundup32(cap);
|
||||||
|
p = (mm_extra_t*)calloc(cap, 4);
|
||||||
|
memcpy(p, r->p, sizeof(mm_extra_t));
|
||||||
|
p->capacity = cap;
|
||||||
|
// update cigar while copying
|
||||||
|
toff = qoff = m = 0;
|
||||||
|
for (k = 0; k < r->p->n_cigar; ++k) {
|
||||||
|
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
||||||
|
if (op == MM_CIGAR_MATCH) {
|
||||||
|
while (len > 0) {
|
||||||
|
// match
|
||||||
|
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l]; ++l) {}
|
||||||
|
if (l > 0) p->cigar[m++] = l << 4 | MM_CIGAR_EQ_MATCH;
|
||||||
|
len -= l;
|
||||||
|
toff += l, qoff += l;
|
||||||
|
// mismatch
|
||||||
|
for (l = 0; l < len && qseq[qoff + l] != tseq[toff + l]; ++l) {}
|
||||||
|
if (l > 0) p->cigar[m++] = l << 4 | MM_CIGAR_X_MISMATCH;
|
||||||
|
len -= l;
|
||||||
|
toff += l, qoff += l;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if (op == MM_CIGAR_INS) {
|
||||||
|
qoff += len;
|
||||||
|
} else if (op == MM_CIGAR_DEL) {
|
||||||
|
toff += len;
|
||||||
|
} else if (op == MM_CIGAR_N_SKIP) {
|
||||||
|
toff += len;
|
||||||
|
}
|
||||||
|
p->cigar[m++] = r->p->cigar[k];
|
||||||
|
}
|
||||||
|
p->n_cigar = m;
|
||||||
|
free(r->p);
|
||||||
|
r->p = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mm_update_extra(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq, const int8_t *mat, int8_t q, int8_t e, int is_eqx, int log_gap)
|
||||||
{
|
{
|
||||||
uint32_t k, l;
|
uint32_t k, l;
|
||||||
int32_t s = 0, max = 0, qshift, tshift, toff = 0, qoff = 0;
|
int32_t qshift, tshift, toff = 0, qoff = 0;
|
||||||
|
double s = 0.0, max = 0.0;
|
||||||
mm_extra_t *p = r->p;
|
mm_extra_t *p = r->p;
|
||||||
if (p == 0) return;
|
if (p == 0) return;
|
||||||
mm_fix_cigar(r, qseq, tseq, &qshift, &tshift, left_aln);
|
mm_fix_cigar(r, qseq, tseq, &qshift, &tshift);
|
||||||
qseq += qshift, tseq += tshift; // qseq and tseq may be shifted due to the removal of leading I/D
|
qseq += qshift, tseq += tshift; // qseq and tseq may be shifted due to the removal of leading I/D
|
||||||
r->blen = r->mlen = 0;
|
r->blen = r->mlen = 0;
|
||||||
for (k = 0; k < p->n_cigar; ++k) {
|
for (k = 0; k < p->n_cigar; ++k) {
|
||||||
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
|
||||||
if (op == 0) { // match/mismatch
|
if (op == MM_CIGAR_MATCH) {
|
||||||
int n_ambi = 0, n_diff = 0;
|
int n_ambi = 0, n_diff = 0;
|
||||||
for (l = 0; l < len; ++l) {
|
for (l = 0; l < len; ++l) {
|
||||||
int cq = qseq[qoff + l], ct = tseq[toff + l];
|
int cq = qseq[qoff + l], ct = tseq[toff + l];
|
||||||
@@ -172,28 +261,31 @@ static void mm_update_extra(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *ts
|
|||||||
}
|
}
|
||||||
r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
|
r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
|
||||||
toff += len, qoff += len;
|
toff += len, qoff += len;
|
||||||
} else if (op == 1) { // insertion
|
} else if (op == MM_CIGAR_INS) {
|
||||||
int n_ambi = 0;
|
int n_ambi = 0;
|
||||||
for (l = 0; l < len; ++l)
|
for (l = 0; l < len; ++l)
|
||||||
if (qseq[qoff + l] > 3) ++n_ambi;
|
if (qseq[qoff + l] > 3) ++n_ambi;
|
||||||
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
||||||
s -= q + e * len;
|
if (log_gap) s -= q + (double)e * mg_log2(1.0 + len);
|
||||||
|
else s -= q + e;
|
||||||
if (s < 0) s = 0;
|
if (s < 0) s = 0;
|
||||||
qoff += len;
|
qoff += len;
|
||||||
} else if (op == 2) { // deletion
|
} else if (op == MM_CIGAR_DEL) {
|
||||||
int n_ambi = 0;
|
int n_ambi = 0;
|
||||||
for (l = 0; l < len; ++l)
|
for (l = 0; l < len; ++l)
|
||||||
if (tseq[toff + l] > 3) ++n_ambi;
|
if (tseq[toff + l] > 3) ++n_ambi;
|
||||||
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
r->blen += len - n_ambi, p->n_ambi += n_ambi;
|
||||||
s -= q + e * len;
|
if (log_gap) s -= q + (double)e * mg_log2(1.0 + len);
|
||||||
|
else s -= q + e;
|
||||||
if (s < 0) s = 0;
|
if (s < 0) s = 0;
|
||||||
toff += len;
|
toff += len;
|
||||||
} else if (op == 3) { // intron
|
} else if (op == MM_CIGAR_N_SKIP) {
|
||||||
toff += len;
|
toff += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->dp_max = max;
|
p->dp_max = (int32_t)(max + .499);
|
||||||
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
|
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
|
||||||
|
if (is_eqx) mm_update_cigar_eqx(r, qseq, tseq); // NB: it has to be called here as changes to qseq and tseq are not returned
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mm_append_cigar(mm_reg1_t *r, uint32_t n_cigar, uint32_t *cigar) // TODO: this calls the libc realloc()
|
static void mm_append_cigar(mm_reg1_t *r, uint32_t n_cigar, uint32_t *cigar) // TODO: this calls the libc realloc()
|
||||||
@@ -221,79 +313,7 @@ static void mm_append_cigar(mm_reg1_t *r, uint32_t n_cigar, uint32_t *cigar) //
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mm_update_cigar_eqx(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq) // written by @armintoepfer
|
static void mm_align_pair(void *km, const mm_mapopt_t *opt, int qlen, const uint8_t *qseq, int tlen, const uint8_t *tseq, const uint8_t *junc, const int8_t *mat, int w, int end_bonus, int zdrop, int flag, ksw_extz_t *ez)
|
||||||
{
|
|
||||||
uint32_t n_EQX = 0;
|
|
||||||
uint32_t k, l, m, cap, toff = 0, qoff = 0, n_M = 0;
|
|
||||||
mm_extra_t *p;
|
|
||||||
if (r->p == 0) return;
|
|
||||||
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
||||||
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
||||||
if (op == 0) {
|
|
||||||
while (len > 0) {
|
|
||||||
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l]; ++l) {} // run of "="; TODO: N<=>N is converted to "="
|
|
||||||
if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
|
|
||||||
|
|
||||||
for (l = 0; l < len && qseq[qoff + l] != tseq[toff + l]; ++l) {} // run of "X"
|
|
||||||
if (l > 0) { ++n_EQX; len -= l; toff += l; qoff += l; }
|
|
||||||
}
|
|
||||||
++n_M;
|
|
||||||
} else if (op == 1) { // insertion
|
|
||||||
qoff += len;
|
|
||||||
} else if (op == 2) { // deletion
|
|
||||||
toff += len;
|
|
||||||
} else if (op == 3) { // intron
|
|
||||||
toff += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// update in-place if we can
|
|
||||||
if (n_EQX == n_M) {
|
|
||||||
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
||||||
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
||||||
if (op == 0) r->p->cigar[k] = len << 4 | 7;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// allocate new storage
|
|
||||||
cap = r->p->n_cigar + (n_EQX - n_M) + sizeof(mm_extra_t);
|
|
||||||
kroundup32(cap);
|
|
||||||
p = (mm_extra_t*)calloc(cap, 4);
|
|
||||||
memcpy(p, r->p, sizeof(mm_extra_t));
|
|
||||||
p->capacity = cap;
|
|
||||||
// update cigar while copying
|
|
||||||
toff = qoff = m = 0;
|
|
||||||
for (k = 0; k < r->p->n_cigar; ++k) {
|
|
||||||
uint32_t op = r->p->cigar[k]&0xf, len = r->p->cigar[k]>>4;
|
|
||||||
if (op == 0) { // match/mismatch
|
|
||||||
while (len > 0) {
|
|
||||||
// match
|
|
||||||
for (l = 0; l < len && qseq[qoff + l] == tseq[toff + l]; ++l) {}
|
|
||||||
if (l > 0) p->cigar[m++] = l << 4 | 7;
|
|
||||||
len -= l;
|
|
||||||
toff += l, qoff += l;
|
|
||||||
// mismatch
|
|
||||||
for (l = 0; l < len && qseq[qoff + l] != tseq[toff + l]; ++l) {}
|
|
||||||
if (l > 0) p->cigar[m++] = l << 4 | 8;
|
|
||||||
len -= l;
|
|
||||||
toff += l, qoff += l;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (op == 1) { // insertion
|
|
||||||
qoff += len;
|
|
||||||
} else if (op == 2) { // deletion
|
|
||||||
toff += len;
|
|
||||||
} else if (op == 3) { // intron
|
|
||||||
toff += len;
|
|
||||||
}
|
|
||||||
p->cigar[m++] = r->p->cigar[k];
|
|
||||||
}
|
|
||||||
p->n_cigar = m;
|
|
||||||
free(r->p);
|
|
||||||
r->p = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mm_align_pair(void *km, const mm_mapopt_t *opt, int qlen, const uint8_t *qseq, int tlen, const uint8_t *tseq, const int8_t *ob, const int8_t *mat,
|
|
||||||
int w, int end_bonus, int zdrop, int flag, ksw_extz_t *ez)
|
|
||||||
{
|
{
|
||||||
if (mm_dbg_flag & MM_DBG_PRINT_ALN_SEQ) {
|
if (mm_dbg_flag & MM_DBG_PRINT_ALN_SEQ) {
|
||||||
int i;
|
int i;
|
||||||
@@ -303,17 +323,20 @@ static void mm_align_pair(void *km, const mm_mapopt_t *opt, int qlen, const uint
|
|||||||
for (i = 0; i < qlen; ++i) fputc("ACGTN"[qseq[i]], stderr);
|
for (i = 0; i < qlen; ++i) fputc("ACGTN"[qseq[i]], stderr);
|
||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
}
|
}
|
||||||
if (opt->flag & MM_F_SPLICE)
|
if (opt->max_sw_mat > 0 && (int64_t)tlen * qlen > opt->max_sw_mat) {
|
||||||
ksw_exts2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->noncan, zdrop, flag, ez);
|
ksw_reset_extz(ez);
|
||||||
|
ez->zdropped = 1;
|
||||||
|
} else if (opt->flag & MM_F_SPLICE)
|
||||||
|
ksw_exts2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, opt->q2, opt->noncan, zdrop, opt->junc_bonus, flag, junc, ez);
|
||||||
else if (opt->q == opt->q2 && opt->e == opt->e2)
|
else if (opt->q == opt->q2 && opt->e == opt->e2)
|
||||||
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, ob, 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) {
|
if (mm_dbg_flag & MM_DBG_PRINT_ALN_SEQ) {
|
||||||
int i;
|
int i;
|
||||||
fprintf(stderr, "score=%d, cigar=", ez->score);
|
fprintf(stderr, "score=%d, cigar=", ez->score);
|
||||||
for (i = 0; i < ez->n_cigar; ++i)
|
for (i = 0; i < ez->n_cigar; ++i)
|
||||||
fprintf(stderr, "%d%c", ez->cigar[i]>>4, "MIDN"[ez->cigar[i]&0xf]);
|
fprintf(stderr, "%d%c", ez->cigar[i]>>4, MM_CIGAR_STR[ez->cigar[i]&0xf]);
|
||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,7 +440,7 @@ static void mm_filter_bad_seeds_alt(void *km, int as1, int cnt1, mm128_t *a, int
|
|||||||
gap2 = ((int32_t)a[as1 + j].y - (int32_t)a[as1 + j - 1].y) - (int32_t)(a[as1 + j].x - a[as1 + j - 1].x);
|
gap2 = ((int32_t)a[as1 + j].y - (int32_t)a[as1 + j - 1].y) - (int32_t)(a[as1 + j].x - a[as1 + j - 1].x);
|
||||||
q_span_pre = a[as1 + j - 1].y >> 32 & 0xff;
|
q_span_pre = a[as1 + j - 1].y >> 32 & 0xff;
|
||||||
rs2 = (int32_t)a[as1 + j - 1].x + q_span_pre;
|
rs2 = (int32_t)a[as1 + j - 1].x + q_span_pre;
|
||||||
qs2 = (int32_t)a[as1 + j - 1].x + q_span_pre;
|
qs2 = (int32_t)a[as1 + j - 1].y + q_span_pre;
|
||||||
m = rs2 - re1 < qs2 - qe1? rs2 - re1 : qs2 - qe1;
|
m = rs2 - re1 < qs2 - qe1? rs2 - re1 : qs2 - qe1;
|
||||||
gap2 = gap2 > 0? gap2 : -gap2;
|
gap2 = gap2 > 0? gap2 : -gap2;
|
||||||
if (m > gap1 + gap2) break;
|
if (m > gap1 + gap2) break;
|
||||||
@@ -513,8 +536,13 @@ static int mm_seed_ext_score(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
|
|||||||
re = re + ext_len < (int32_t)mi->seq[rid].len? re + ext_len : mi->seq[rid].len;
|
re = re + ext_len < (int32_t)mi->seq[rid].len? re + ext_len : mi->seq[rid].len;
|
||||||
qe = qe + ext_len < qlen? qe + ext_len : qlen;
|
qe = qe + ext_len < qlen? qe + ext_len : qlen;
|
||||||
tseq = (uint8_t*)kmalloc(km, re - rs);
|
tseq = (uint8_t*)kmalloc(km, re - rs);
|
||||||
mm_idx_getseq(mi, rid, rs, re, tseq);
|
if (opt->flag & MM_F_QSTRAND) {
|
||||||
qseq = qseq0[a->x>>63] + qs;
|
qseq = qseq0[0] + qs;
|
||||||
|
mm_idx_getseq2(mi, a->x>>63, rid, rs, re, tseq);
|
||||||
|
} else {
|
||||||
|
qseq = qseq0[a->x>>63] + qs;
|
||||||
|
mm_idx_getseq(mi, rid, rs, re, tseq);
|
||||||
|
}
|
||||||
qp = ksw_ll_qinit(km, 2, qe - qs, qseq, 5, mat);
|
qp = ksw_ll_qinit(km, 2, qe - qs, qseq, 5, mat);
|
||||||
score = ksw_ll_i16(qp, re - rs, tseq, opt->q, opt->e, &q_off, &t_off);
|
score = ksw_ll_i16(qp, re - rs, tseq, opt->q, opt->e, &q_off, &t_off);
|
||||||
kfree(km, tseq);
|
kfree(km, tseq);
|
||||||
@@ -546,11 +574,11 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
{
|
{
|
||||||
int is_sr = !!(opt->flag & MM_F_SR), is_splice = !!(opt->flag & MM_F_SPLICE);
|
int is_sr = !!(opt->flag & MM_F_SR), is_splice = !!(opt->flag & MM_F_SPLICE);
|
||||||
int32_t rid = a[r->as].x<<1>>33, rev = a[r->as].x>>63, as1, cnt1;
|
int32_t rid = a[r->as].x<<1>>33, rev = a[r->as].x>>63, as1, cnt1;
|
||||||
uint8_t *tseq, *qseq;
|
uint8_t *tseq, *qseq, *junc;
|
||||||
int32_t i, l, bw, dropped = 0, extra_flag = 0, rs0, re0, qs0, qe0;
|
int32_t i, l, bw, bw_long, dropped = 0, extra_flag = 0, rs0, re0, qs0, qe0;
|
||||||
int32_t rs, re, qs, qe;
|
int32_t rs, re, qs, qe;
|
||||||
int32_t rs1, qs1, re1, qe1;
|
int32_t rs1, qs1, re1, qe1;
|
||||||
int8_t mat[25], *ob;
|
int8_t mat[25];
|
||||||
|
|
||||||
if (is_sr) assert(!(mi->flag & MM_I_HPC)); // HPC won't work with SR because with HPC we can't easily tell if there is a gap
|
if (is_sr) assert(!(mi->flag & MM_I_HPC)); // HPC won't work with SR because with HPC we can't easily tell if there is a gap
|
||||||
|
|
||||||
@@ -558,6 +586,8 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
if (r->cnt == 0) return;
|
if (r->cnt == 0) return;
|
||||||
ksw_gen_simple_mat(5, mat, opt->a, opt->b, opt->sc_ambi);
|
ksw_gen_simple_mat(5, mat, opt->a, opt->b, opt->sc_ambi);
|
||||||
bw = (int)(opt->bw * 1.5 + 1.);
|
bw = (int)(opt->bw * 1.5 + 1.);
|
||||||
|
bw_long = (int)(opt->bw_long * 1.5 + 1.);
|
||||||
|
if (bw_long < bw) bw_long = bw;
|
||||||
|
|
||||||
if (is_sr && !(mi->flag & MM_I_HPC)) {
|
if (is_sr && !(mi->flag & MM_I_HPC)) {
|
||||||
mm_max_stretch(r, a, &as1, &cnt1);
|
mm_max_stretch(r, a, &as1, &cnt1);
|
||||||
@@ -594,11 +624,9 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
qs0 = 0, qe0 = qlen;
|
qs0 = 0, qe0 = qlen;
|
||||||
l = qs;
|
l = qs;
|
||||||
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
||||||
l = l < opt->bw? l : opt->bw;
|
|
||||||
rs0 = rs - l > 0? rs - l : 0;
|
rs0 = rs - l > 0? rs - l : 0;
|
||||||
l = qlen - qe;
|
l = qlen - qe;
|
||||||
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
l += l * opt->a + opt->end_bonus > opt->q? (l * opt->a + opt->end_bonus - opt->q) / opt->e : 0;
|
||||||
l = l < opt->bw? l : opt->bw;
|
|
||||||
re0 = re + l < (int32_t)mi->seq[rid].len? re + l : mi->seq[rid].len;
|
re0 = re + l < (int32_t)mi->seq[rid].len? re + l : mi->seq[rid].len;
|
||||||
} else {
|
} else {
|
||||||
// compute rs0 and qs0
|
// compute rs0 and qs0
|
||||||
@@ -614,6 +642,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
if (++l > opt->min_cnt) {
|
if (++l > opt->min_cnt) {
|
||||||
l = rs0 - x > qs0 - y? rs0 - x : qs0 - y;
|
l = rs0 - x > qs0 - y? rs0 - x : qs0 - y;
|
||||||
rs1 = rs0 - l, qs1 = qs0 - l;
|
rs1 = rs0 - l, qs1 = qs0 - l;
|
||||||
|
if (rs1 < 0) rs1 = 0; // not strictly necessary; better have this guard for explicit
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,6 +656,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
l = l < rs? l : rs;
|
l = l < rs? l : rs;
|
||||||
rs1 = rs1 > rs - l? rs1 : rs - l;
|
rs1 = rs1 > rs - l? rs1 : rs - l;
|
||||||
rs0 = rs0 < rs1? rs0 : rs1;
|
rs0 = rs0 < rs1? rs0 : rs1;
|
||||||
|
rs0 = rs0 < rs? rs0 : rs;
|
||||||
} else rs0 = rs, qs0 = qs;
|
} else rs0 = rs, qs0 = qs;
|
||||||
// compute re0 and qe0
|
// compute re0 and qe0
|
||||||
re0 = (int32_t)a[r->as + r->cnt - 1].x + 1;
|
re0 = (int32_t)a[r->as + r->cnt - 1].x + 1;
|
||||||
@@ -665,14 +695,21 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
|
|
||||||
assert(re0 > rs0);
|
assert(re0 > rs0);
|
||||||
tseq = (uint8_t*)kmalloc(km, re0 - rs0);
|
tseq = (uint8_t*)kmalloc(km, re0 - rs0);
|
||||||
ob = (int8_t*)kmalloc(km, re0 - rs0);
|
junc = (uint8_t*)kmalloc(km, re0 - rs0);
|
||||||
|
|
||||||
if (qs > 0 && rs > 0) { // left extension
|
if (qs > 0 && rs > 0) { // left extension; probably the condition can be changed to "qs > qs0 && rs > rs0"
|
||||||
qseq = &qseq0[rev][qs0];
|
if (opt->flag & MM_F_QSTRAND) {
|
||||||
mm_idx_getseq2(mi, rid, rs0, rs, tseq, ob);
|
qseq = &qseq0[0][qs0];
|
||||||
|
mm_idx_getseq2(mi, rev, rid, rs0, rs, tseq);
|
||||||
|
} else {
|
||||||
|
qseq = &qseq0[rev][qs0];
|
||||||
|
mm_idx_getseq(mi, rid, rs0, rs, tseq);
|
||||||
|
}
|
||||||
|
mm_idx_bed_junc(mi, rid, rs0, rs, junc);
|
||||||
mm_seq_rev(qs - qs0, qseq);
|
mm_seq_rev(qs - qs0, qseq);
|
||||||
mm_seq_rev(rs - rs0, tseq);
|
mm_seq_rev(rs - rs0, tseq);
|
||||||
mm_align_pair(km, opt, qs - qs0, qseq, rs - rs0, tseq, ob, mat, bw, opt->end_bonus, r->split_inv? opt->zdrop_inv : opt->zdrop, extra_flag|KSW_EZ_EXTZ_ONLY|KSW_EZ_RIGHT|KSW_EZ_REV_CIGAR, ez);
|
mm_seq_rev(rs - rs0, junc);
|
||||||
|
mm_align_pair(km, opt, qs - qs0, qseq, rs - rs0, tseq, junc, mat, bw, opt->end_bonus, r->split_inv? opt->zdrop_inv : opt->zdrop, extra_flag|KSW_EZ_EXTZ_ONLY|KSW_EZ_RIGHT|KSW_EZ_REV_CIGAR, ez);
|
||||||
if (ez->n_cigar > 0) {
|
if (ez->n_cigar > 0) {
|
||||||
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
||||||
r->p->dp_score += ez->max;
|
r->p->dp_score += ez->max;
|
||||||
@@ -692,12 +729,18 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
} else mm_adjust_minier(mi, qseq0, &a[as1 + i], &re, &qe);
|
} else mm_adjust_minier(mi, qseq0, &a[as1 + i], &re, &qe);
|
||||||
re1 = re, qe1 = qe;
|
re1 = re, qe1 = qe;
|
||||||
if (i == cnt1 - 1 || (a[as1+i].y&MM_SEED_LONG_JOIN) || (qe - qs >= opt->min_ksw_len && re - rs >= opt->min_ksw_len)) {
|
if (i == cnt1 - 1 || (a[as1+i].y&MM_SEED_LONG_JOIN) || (qe - qs >= opt->min_ksw_len && re - rs >= opt->min_ksw_len)) {
|
||||||
int j, bw1 = bw, zdrop_code;
|
int j, bw1 = bw_long, zdrop_code;
|
||||||
if (a[as1+i].y & MM_SEED_LONG_JOIN)
|
if (a[as1+i].y & MM_SEED_LONG_JOIN)
|
||||||
bw1 = qe - qs > re - rs? qe - qs : re - rs;
|
bw1 = qe - qs > re - rs? qe - qs : re - rs;
|
||||||
// perform alignment
|
// perform alignment
|
||||||
qseq = &qseq0[rev][qs];
|
if (opt->flag & MM_F_QSTRAND) {
|
||||||
mm_idx_getseq2(mi, rid, rs, re, tseq, ob);
|
qseq = &qseq0[0][qs];
|
||||||
|
mm_idx_getseq2(mi, rev, rid, rs, re, tseq);
|
||||||
|
} else {
|
||||||
|
qseq = &qseq0[rev][qs];
|
||||||
|
mm_idx_getseq(mi, rid, rs, re, tseq);
|
||||||
|
}
|
||||||
|
mm_idx_bed_junc(mi, rid, rs, re, junc);
|
||||||
if (is_sr) { // perform ungapped alignment
|
if (is_sr) { // perform ungapped alignment
|
||||||
assert(qe - qs == re - rs);
|
assert(qe - qs == re - rs);
|
||||||
ksw_reset_extz(ez);
|
ksw_reset_extz(ez);
|
||||||
@@ -705,17 +748,24 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
if (qseq[j] >= 4 || tseq[j] >= 4) ez->score += opt->e2;
|
if (qseq[j] >= 4 || tseq[j] >= 4) ez->score += opt->e2;
|
||||||
else ez->score += qseq[j] == tseq[j]? opt->a : -opt->b;
|
else ez->score += qseq[j] == tseq[j]? opt->a : -opt->b;
|
||||||
}
|
}
|
||||||
ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, 0, qe - qs);
|
ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, MM_CIGAR_MATCH, qe - qs);
|
||||||
} else { // perform normal gapped alignment
|
} else { // perform normal gapped alignment
|
||||||
mm_align_pair(km, opt, qe - qs, qseq, re - rs, tseq, ob, mat, bw1, -1, opt->zdrop, extra_flag|KSW_EZ_APPROX_MAX, ez); // first pass: with approximate Z-drop
|
mm_align_pair(km, opt, qe - qs, qseq, re - rs, tseq, junc, mat, bw1, -1, opt->zdrop, extra_flag|KSW_EZ_APPROX_MAX, ez); // first pass: with approximate Z-drop
|
||||||
}
|
}
|
||||||
// test Z-drop and inversion Z-drop
|
// test Z-drop and inversion Z-drop
|
||||||
if ((zdrop_code = mm_test_zdrop(km, opt, qseq, tseq, ez->n_cigar, ez->cigar, mat)) != 0)
|
if ((zdrop_code = mm_test_zdrop(km, opt, qseq, tseq, ez->n_cigar, ez->cigar, mat)) != 0)
|
||||||
mm_align_pair(km, opt, qe - qs, qseq, re - rs, tseq, ob, mat, bw1, -1, zdrop_code == 2? opt->zdrop_inv : opt->zdrop, extra_flag, ez); // second pass: lift approximate
|
mm_align_pair(km, opt, qe - qs, qseq, re - rs, tseq, junc, mat, bw1, -1, zdrop_code == 2? opt->zdrop_inv : opt->zdrop, extra_flag, ez); // second pass: lift approximate
|
||||||
// update CIGAR
|
// update CIGAR
|
||||||
if (ez->n_cigar > 0)
|
if (ez->n_cigar > 0)
|
||||||
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
||||||
if (ez->zdropped) { // truncated by Z-drop; TODO: sometimes Z-drop kicks in because the next seed placement is wrong. This can be fixed in principle.
|
if (ez->zdropped) { // truncated by Z-drop; TODO: sometimes Z-drop kicks in because the next seed placement is wrong. This can be fixed in principle.
|
||||||
|
if (!r->p) {
|
||||||
|
assert(ez->n_cigar == 0);
|
||||||
|
uint32_t capacity = sizeof(mm_extra_t)/4;
|
||||||
|
kroundup32(capacity);
|
||||||
|
r->p = (mm_extra_t*)calloc(capacity, 4);
|
||||||
|
r->p->capacity = capacity;
|
||||||
|
}
|
||||||
for (j = i - 1; j >= 0; --j)
|
for (j = i - 1; j >= 0; --j)
|
||||||
if ((int32_t)a[as1 + j].x <= rs + ez->max_t)
|
if ((int32_t)a[as1 + j].x <= rs + ez->max_t)
|
||||||
break;
|
break;
|
||||||
@@ -725,7 +775,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
re1 = rs + (ez->max_t + 1);
|
re1 = rs + (ez->max_t + 1);
|
||||||
qe1 = qs + (ez->max_q + 1);
|
qe1 = qs + (ez->max_q + 1);
|
||||||
if (cnt1 - (j + 1) >= opt->min_cnt) {
|
if (cnt1 - (j + 1) >= opt->min_cnt) {
|
||||||
mm_split_reg(r, r2, as1 + j + 1 - r->as, qlen, a);
|
mm_split_reg(r, r2, as1 + j + 1 - r->as, qlen, a, !!(opt->flag&MM_F_QSTRAND));
|
||||||
if (zdrop_code == 2) r2->split_inv = 1;
|
if (zdrop_code == 2) r2->split_inv = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -735,9 +785,15 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!dropped && qe < qe0 && re < re0) { // right extension
|
if (!dropped && qe < qe0 && re < re0) { // right extension
|
||||||
qseq = &qseq0[rev][qe];
|
if (opt->flag & MM_F_QSTRAND) {
|
||||||
mm_idx_getseq2(mi, rid, re, re0, tseq, ob);
|
qseq = &qseq0[0][qe];
|
||||||
mm_align_pair(km, opt, qe0 - qe, qseq, re0 - re, tseq, ob, mat, bw, opt->end_bonus, opt->zdrop, extra_flag|KSW_EZ_EXTZ_ONLY, ez);
|
mm_idx_getseq2(mi, rev, rid, re, re0, tseq);
|
||||||
|
} else {
|
||||||
|
qseq = &qseq0[rev][qe];
|
||||||
|
mm_idx_getseq(mi, rid, re, re0, tseq);
|
||||||
|
}
|
||||||
|
mm_idx_bed_junc(mi, rid, re, re0, junc);
|
||||||
|
mm_align_pair(km, opt, qe0 - qe, qseq, re0 - re, tseq, junc, mat, bw, opt->end_bonus, opt->zdrop, extra_flag|KSW_EZ_EXTZ_ONLY, ez);
|
||||||
if (ez->n_cigar > 0) {
|
if (ez->n_cigar > 0) {
|
||||||
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
mm_append_cigar(r, ez->n_cigar, ez->cigar);
|
||||||
r->p->dp_score += ez->max;
|
r->p->dp_score += ez->max;
|
||||||
@@ -748,25 +804,29 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
|
|||||||
assert(qe1 <= qlen);
|
assert(qe1 <= qlen);
|
||||||
|
|
||||||
r->rs = rs1, r->re = re1;
|
r->rs = rs1, r->re = re1;
|
||||||
if (rev) r->qs = qlen - qe1, r->qe = qlen - qs1;
|
if (!rev || (opt->flag & MM_F_QSTRAND)) r->qs = qs1, r->qe = qe1;
|
||||||
else r->qs = qs1, r->qe = qe1;
|
else r->qs = qlen - qe1, r->qe = qlen - qs1;
|
||||||
|
|
||||||
assert(re1 - rs1 <= re0 - rs0);
|
assert(re1 - rs1 <= re0 - rs0);
|
||||||
if (r->p) {
|
if (r->p) {
|
||||||
int left_aln = (opt->flag & MM_F_SPLICE) || mi->n_R == 0? 1 : 0;
|
if (opt->flag & MM_F_QSTRAND) {
|
||||||
mm_idx_getseq2(mi, rid, rs1, re1, tseq, ob);
|
mm_idx_getseq2(mi, r->rev, rid, rs1, re1, tseq);
|
||||||
mm_update_extra(r, &qseq0[r->rev][qs1], tseq, mat, opt->q, opt->e, left_aln);
|
qseq = &qseq0[0][qs1];
|
||||||
if (opt->flag & MM_F_EQX) mm_update_cigar_eqx(r, &qseq0[r->rev][qs1], tseq);
|
} else {
|
||||||
|
mm_idx_getseq(mi, rid, rs1, re1, tseq);
|
||||||
|
qseq = &qseq0[r->rev][qs1];
|
||||||
|
}
|
||||||
|
mm_update_extra(r, qseq, tseq, mat, opt->q, opt->e, opt->flag & MM_F_EQX, !(opt->flag & MM_F_SR));
|
||||||
if (rev && r->p->trans_strand)
|
if (rev && r->p->trans_strand)
|
||||||
r->p->trans_strand ^= 3; // flip to the read strand
|
r->p->trans_strand ^= 3; // flip to the read strand
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(km, tseq);
|
kfree(km, tseq);
|
||||||
kfree(km, ob);
|
kfree(km, junc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], const mm_reg1_t *r1, const mm_reg1_t *r2, mm_reg1_t *r_inv, ksw_extz_t *ez)
|
static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], const mm_reg1_t *r1, const mm_reg1_t *r2, mm_reg1_t *r_inv, ksw_extz_t *ez)
|
||||||
{
|
{ // NB: this doesn't work with the qstrand mode
|
||||||
int tl, ql, score, ret = 0, q_off, t_off;
|
int tl, ql, score, ret = 0, q_off, t_off;
|
||||||
uint8_t *tseq, *qseq;
|
uint8_t *tseq, *qseq;
|
||||||
int8_t mat[25];
|
int8_t mat[25];
|
||||||
@@ -815,8 +875,7 @@ static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, i
|
|||||||
}
|
}
|
||||||
r_inv->rs = r1->re + t_off;
|
r_inv->rs = r1->re + t_off;
|
||||||
r_inv->re = r_inv->rs + ez->max_t + 1;
|
r_inv->re = r_inv->rs + ez->max_t + 1;
|
||||||
mm_update_extra(r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e, 0);
|
mm_update_extra(r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e, opt->flag & MM_F_EQX, !(opt->flag & MM_F_SR));
|
||||||
if (opt->flag & MM_F_EQX) mm_update_cigar_eqx(r_inv, &qseq[q_off], &tseq[t_off]);
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
end_align1_inv:
|
end_align1_inv:
|
||||||
kfree(km, tseq);
|
kfree(km, tseq);
|
||||||
@@ -833,6 +892,71 @@ static inline mm_reg1_t *mm_insert_reg(const mm_reg1_t *r, int i, int *n_regs, m
|
|||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void mm_count_gaps(const mm_reg1_t *r, int32_t *n_gap_, int32_t *n_gapo_)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
int32_t n_gapo = 0, n_gap = 0;
|
||||||
|
*n_gap_ = *n_gapo_ = -1;
|
||||||
|
if (r->p == 0) return;
|
||||||
|
for (i = 0; i < r->p->n_cigar; ++i) {
|
||||||
|
int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
|
||||||
|
if (op == MM_CIGAR_INS || op == MM_CIGAR_DEL)
|
||||||
|
++n_gapo, n_gap += len;
|
||||||
|
}
|
||||||
|
*n_gap_ = n_gap, *n_gapo_ = n_gapo;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mm_event_identity(const mm_reg1_t *r)
|
||||||
|
{
|
||||||
|
int32_t n_gap, n_gapo;
|
||||||
|
if (r->p == 0) return -1.0f;
|
||||||
|
mm_count_gaps(r, &n_gap, &n_gapo);
|
||||||
|
return (double)r->mlen / (r->blen + r->p->n_ambi - n_gap + n_gapo);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t mm_recal_max_dp(const mm_reg1_t *r, double b2, int32_t match_sc)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
int32_t n_gap = 0, n_gapo = 0, n_mis;
|
||||||
|
double gap_cost = 0.0;
|
||||||
|
if (r->p == 0) return -1;
|
||||||
|
for (i = 0; i < r->p->n_cigar; ++i) {
|
||||||
|
int32_t op = r->p->cigar[i] & 0xf, len = r->p->cigar[i] >> 4;
|
||||||
|
if (op == MM_CIGAR_INS || op == MM_CIGAR_DEL) {
|
||||||
|
gap_cost += b2 + (double)mg_log2(1.0 + len);
|
||||||
|
++n_gapo, n_gap += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n_mis = r->blen + r->p->n_ambi - r->mlen - n_gap;
|
||||||
|
return (int32_t)(match_sc * (r->mlen - b2 * n_mis - gap_cost) + .499);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm_update_dp_max(int qlen, int n_regs, mm_reg1_t *regs, float frac, int a, int b)
|
||||||
|
{
|
||||||
|
int32_t max = -1, max2 = -1, i, max_i = -1;
|
||||||
|
double div, b2;
|
||||||
|
if (n_regs < 2) return;
|
||||||
|
for (i = 0; i < n_regs; ++i) {
|
||||||
|
mm_reg1_t *r = ®s[i];
|
||||||
|
if (r->p == 0) continue;
|
||||||
|
if (r->p->dp_max > max) max2 = max, max = r->p->dp_max, max_i = i;
|
||||||
|
else if (r->p->dp_max > max2) max2 = r->p->dp_max;
|
||||||
|
}
|
||||||
|
if (max_i < 0 || max < 0 || max2 < 0) return;
|
||||||
|
if (regs[max_i].qe - regs[max_i].qs < (double)qlen * frac) return;
|
||||||
|
if (max2 < (double)max * frac) return;
|
||||||
|
div = 1. - mm_event_identity(®s[max_i]);
|
||||||
|
if (div < 0.02) div = 0.02;
|
||||||
|
b2 = 0.5 / div; // max value: 25
|
||||||
|
if (b2 * a < b) b2 = (double)a / b;
|
||||||
|
for (i = 0; i < n_regs; ++i) {
|
||||||
|
mm_reg1_t *r = ®s[i];
|
||||||
|
if (r->p == 0) continue;
|
||||||
|
r->p->dp_max = mm_recal_max_dp(r, b2, a);
|
||||||
|
if (r->p->dp_max < 0) r->p->dp_max = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a)
|
mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a)
|
||||||
{
|
{
|
||||||
extern unsigned char seq_nt4_table[256];
|
extern unsigned char seq_nt4_table[256];
|
||||||
@@ -876,7 +1000,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 (i > 0 && regs[i].split_inv) {
|
if (i > 0 && regs[i].split_inv && !(opt->flag & MM_F_NO_INV)) {
|
||||||
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
|
||||||
@@ -887,6 +1011,10 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
|
|||||||
kfree(km, qseq0[0]);
|
kfree(km, qseq0[0]);
|
||||||
kfree(km, ez.cigar);
|
kfree(km, ez.cigar);
|
||||||
mm_filter_regs(opt, qlen, n_regs_, regs);
|
mm_filter_regs(opt, qlen, n_regs_, regs);
|
||||||
mm_hit_sort(km, n_regs_, regs);
|
if (!(opt->flag&MM_F_SR) && !opt->split_prefix && qlen >= opt->rank_min_len) {
|
||||||
|
mm_update_dp_max(qlen, *n_regs_, regs, opt->rank_frac, opt->a, opt->b);
|
||||||
|
mm_filter_regs(opt, qlen, n_regs_, regs);
|
||||||
|
}
|
||||||
|
mm_hit_sort(km, n_regs_, regs, opt->alt_drop);
|
||||||
return regs;
|
return regs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ unsigned char seq_comp_table[256] = {
|
|||||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
|
||||||
64, 'T', 'V', 'G', 'H', 'E', 'F', 'C', 'D', 'I', 'J', 'M', 'L', 'K', 'N', 'O',
|
64, 'T', 'V', 'G', 'H', 'E', 'F', 'C', 'D', 'I', 'J', 'M', 'L', 'K', 'N', 'O',
|
||||||
'P', 'Q', 'Y', 'S', 'A', 'A', 'B', 'W', 'X', 'R', 'Z', 91, 92, 93, 94, 95,
|
'P', 'Q', 'Y', 'S', 'A', 'A', 'B', 'W', 'X', 'R', 'Z', 91, 92, 93, 94, 95,
|
||||||
64, 't', 'v', 'g', 'h', 'e', 'f', 'c', 'd', 'i', 'j', 'm', 'l', 'k', 'n', 'o',
|
96, 't', 'v', 'g', 'h', 'e', 'f', 'c', 'd', 'i', 'j', 'm', 'l', 'k', 'n', 'o',
|
||||||
'p', 'q', 'y', 's', 'a', 'a', 'b', 'w', 'x', 'r', 'z', 123, 124, 125, 126, 127,
|
'p', 'q', 'y', 's', 'a', 'a', 'b', 'w', 'x', 'r', 'z', 123, 124, 125, 126, 127,
|
||||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
|
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
|
||||||
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
|
||||||
@@ -39,7 +39,7 @@ mm_bseq_file_t *mm_bseq_open(const char *fn)
|
|||||||
{
|
{
|
||||||
mm_bseq_file_t *fp;
|
mm_bseq_file_t *fp;
|
||||||
gzFile f;
|
gzFile f;
|
||||||
f = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
|
f = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(0, "r");
|
||||||
if (f == 0) return 0;
|
if (f == 0) return 0;
|
||||||
fp = (mm_bseq_file_t*)calloc(1, sizeof(mm_bseq_file_t));
|
fp = (mm_bseq_file_t*)calloc(1, sizeof(mm_bseq_file_t));
|
||||||
fp->fp = f;
|
fp->fp = f;
|
||||||
@@ -65,6 +65,8 @@ static inline char *kstrdup(const kstring_t *s)
|
|||||||
static inline void kseq2bseq(kseq_t *ks, mm_bseq1_t *s, int with_qual, int with_comment)
|
static inline void kseq2bseq(kseq_t *ks, mm_bseq1_t *s, int with_qual, int with_comment)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
if (ks->name.l == 0)
|
||||||
|
fprintf(stderr, "[WARNING]\033[1;31m empty sequence name in the input.\033[0m\n");
|
||||||
s->name = kstrdup(&ks->name);
|
s->name = kstrdup(&ks->name);
|
||||||
s->seq = kstrdup(&ks->seq);
|
s->seq = kstrdup(&ks->seq);
|
||||||
for (i = 0; i < (int)ks->seq.l; ++i) // convert U to T
|
for (i = 0; i < (int)ks->seq.l; ++i) // convert U to T
|
||||||
@@ -75,9 +77,10 @@ static inline void kseq2bseq(kseq_t *ks, mm_bseq1_t *s, int with_qual, int with_
|
|||||||
s->l_seq = ks->seq.l;
|
s->l_seq = ks->seq.l;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int chunk_size, int with_qual, int with_comment, int frag_mode, int *n_)
|
mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int with_comment, int frag_mode, int *n_)
|
||||||
{
|
{
|
||||||
int64_t size = 0;
|
int64_t size = 0;
|
||||||
|
int ret;
|
||||||
kvec_t(mm_bseq1_t) a = {0,0,0};
|
kvec_t(mm_bseq1_t) a = {0,0,0};
|
||||||
kseq_t *ks = fp->ks;
|
kseq_t *ks = fp->ks;
|
||||||
*n_ = 0;
|
*n_ = 0;
|
||||||
@@ -87,7 +90,7 @@ mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int chunk_size, int with_qual, int
|
|||||||
size = fp->s.l_seq;
|
size = fp->s.l_seq;
|
||||||
memset(&fp->s, 0, sizeof(mm_bseq1_t));
|
memset(&fp->s, 0, sizeof(mm_bseq1_t));
|
||||||
}
|
}
|
||||||
while (kseq_read(ks) >= 0) {
|
while ((ret = kseq_read(ks)) >= 0) {
|
||||||
mm_bseq1_t *s;
|
mm_bseq1_t *s;
|
||||||
assert(ks->seq.l <= INT32_MAX);
|
assert(ks->seq.l <= INT32_MAX);
|
||||||
if (a.m == 0) kv_resize(mm_bseq1_t, 0, a, 256);
|
if (a.m == 0) kv_resize(mm_bseq1_t, 0, a, 256);
|
||||||
@@ -96,7 +99,7 @@ mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int chunk_size, int with_qual, int
|
|||||||
size += s->l_seq;
|
size += s->l_seq;
|
||||||
if (size >= chunk_size) {
|
if (size >= chunk_size) {
|
||||||
if (frag_mode && a.a[a.n-1].l_seq < CHECK_PAIR_THRES) {
|
if (frag_mode && a.a[a.n-1].l_seq < CHECK_PAIR_THRES) {
|
||||||
while (kseq_read(ks) >= 0) {
|
while ((ret = kseq_read(ks)) >= 0) {
|
||||||
kseq2bseq(ks, &fp->s, with_qual, with_comment);
|
kseq2bseq(ks, &fp->s, with_qual, with_comment);
|
||||||
if (mm_qname_same(fp->s.name, a.a[a.n-1].name)) {
|
if (mm_qname_same(fp->s.name, a.a[a.n-1].name)) {
|
||||||
kv_push(mm_bseq1_t, 0, a, fp->s);
|
kv_push(mm_bseq1_t, 0, a, fp->s);
|
||||||
@@ -107,21 +110,25 @@ mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int chunk_size, int with_qual, int
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret < -1) {
|
||||||
|
if (a.n) fprintf(stderr, "[WARNING]\033[1;31m failed to parse the FASTA/FASTQ record next to '%s'. Continue anyway.\033[0m\n", a.a[a.n-1].name);
|
||||||
|
else fprintf(stderr, "[WARNING]\033[1;31m failed to parse the first FASTA/FASTQ record. Continue anyway.\033[0m\n");
|
||||||
|
}
|
||||||
*n_ = a.n;
|
*n_ = a.n;
|
||||||
return a.a;
|
return a.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_bseq1_t *mm_bseq_read2(mm_bseq_file_t *fp, int chunk_size, int with_qual, int frag_mode, int *n_)
|
mm_bseq1_t *mm_bseq_read2(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int frag_mode, int *n_)
|
||||||
{
|
{
|
||||||
return mm_bseq_read3(fp, chunk_size, with_qual, 0, frag_mode, n_);
|
return mm_bseq_read3(fp, chunk_size, with_qual, 0, frag_mode, n_);
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_bseq1_t *mm_bseq_read(mm_bseq_file_t *fp, int chunk_size, int with_qual, int *n_)
|
mm_bseq1_t *mm_bseq_read(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int *n_)
|
||||||
{
|
{
|
||||||
return mm_bseq_read2(fp, chunk_size, with_qual, 0, n_);
|
return mm_bseq_read2(fp, chunk_size, with_qual, 0, n_);
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_bseq1_t *mm_bseq_read_frag2(int n_fp, mm_bseq_file_t **fp, int chunk_size, int with_qual, int with_comment, int *n_)
|
mm_bseq1_t *mm_bseq_read_frag2(int n_fp, mm_bseq_file_t **fp, int64_t chunk_size, int with_qual, int with_comment, int *n_)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int64_t size = 0;
|
int64_t size = 0;
|
||||||
@@ -151,7 +158,7 @@ mm_bseq1_t *mm_bseq_read_frag2(int n_fp, mm_bseq_file_t **fp, int chunk_size, in
|
|||||||
return a.a;
|
return a.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_bseq1_t *mm_bseq_read_frag(int n_fp, mm_bseq_file_t **fp, int chunk_size, int with_qual, int *n_)
|
mm_bseq1_t *mm_bseq_read_frag(int n_fp, mm_bseq_file_t **fp, int64_t chunk_size, int with_qual, int *n_)
|
||||||
{
|
{
|
||||||
return mm_bseq_read_frag2(n_fp, fp, chunk_size, with_qual, 0, n_);
|
return mm_bseq_read_frag2(n_fp, fp, chunk_size, with_qual, 0, n_);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ typedef struct {
|
|||||||
|
|
||||||
mm_bseq_file_t *mm_bseq_open(const char *fn);
|
mm_bseq_file_t *mm_bseq_open(const char *fn);
|
||||||
void mm_bseq_close(mm_bseq_file_t *fp);
|
void mm_bseq_close(mm_bseq_file_t *fp);
|
||||||
mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int chunk_size, int with_qual, int with_comment, int frag_mode, int *n_);
|
mm_bseq1_t *mm_bseq_read3(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int with_comment, int frag_mode, int *n_);
|
||||||
mm_bseq1_t *mm_bseq_read2(mm_bseq_file_t *fp, int chunk_size, int with_qual, int frag_mode, int *n_);
|
mm_bseq1_t *mm_bseq_read2(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int frag_mode, int *n_);
|
||||||
mm_bseq1_t *mm_bseq_read(mm_bseq_file_t *fp, int chunk_size, int with_qual, int *n_);
|
mm_bseq1_t *mm_bseq_read(mm_bseq_file_t *fp, int64_t chunk_size, int with_qual, int *n_);
|
||||||
mm_bseq1_t *mm_bseq_read_frag2(int n_fp, mm_bseq_file_t **fp, int chunk_size, int with_qual, int with_comment, int *n_);
|
mm_bseq1_t *mm_bseq_read_frag2(int n_fp, mm_bseq_file_t **fp, int64_t chunk_size, int with_qual, int with_comment, int *n_);
|
||||||
mm_bseq1_t *mm_bseq_read_frag(int n_fp, mm_bseq_file_t **fp, int chunk_size, int with_qual, int *n_);
|
mm_bseq1_t *mm_bseq_read_frag(int n_fp, mm_bseq_file_t **fp, int64_t chunk_size, int with_qual, int *n_);
|
||||||
int mm_bseq_eof(mm_bseq_file_t *fp);
|
int mm_bseq_eof(mm_bseq_file_t *fp);
|
||||||
|
|
||||||
extern unsigned char seq_nt4_table[256];
|
extern unsigned char seq_nt4_table[256];
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "minimap.h"
|
|
||||||
#include "mmpriv.h"
|
|
||||||
#include "kalloc.h"
|
|
||||||
|
|
||||||
static const char LogTable256[256] = {
|
|
||||||
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
|
|
||||||
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
||||||
LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
|
|
||||||
LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline int ilog2_32(uint32_t v)
|
|
||||||
{
|
|
||||||
register uint32_t t, tt;
|
|
||||||
if ((tt = v>>16)) return (t = tt>>8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
|
|
||||||
return (t = v>>8) ? 8 + LogTable256[t] : LogTable256[v];
|
|
||||||
}
|
|
||||||
|
|
||||||
mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int min_cnt, int min_sc, int is_cdna, int n_segs, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km)
|
|
||||||
{ // TODO: make sure this works when n has more than 32 bits
|
|
||||||
int32_t k, *f, *p, *t, *v, n_u, n_v;
|
|
||||||
int64_t i, j, st = 0;
|
|
||||||
uint64_t *u, *u2, sum_qspan = 0;
|
|
||||||
float avg_qspan;
|
|
||||||
mm128_t *b, *w;
|
|
||||||
|
|
||||||
if (_u) *_u = 0, *n_u_ = 0;
|
|
||||||
f = (int32_t*)kmalloc(km, n * 4);
|
|
||||||
p = (int32_t*)kmalloc(km, n * 4);
|
|
||||||
t = (int32_t*)kmalloc(km, n * 4);
|
|
||||||
v = (int32_t*)kmalloc(km, n * 4);
|
|
||||||
memset(t, 0, n * 4);
|
|
||||||
|
|
||||||
for (i = 0; i < n; ++i) sum_qspan += a[i].y>>32&0xff;
|
|
||||||
avg_qspan = (float)sum_qspan / n;
|
|
||||||
|
|
||||||
// fill the score and backtrack arrays
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
uint64_t ri = a[i].x;
|
|
||||||
int64_t max_j = -1;
|
|
||||||
int32_t qi = (int32_t)a[i].y, q_span = a[i].y>>32&0xff; // NB: only 8 bits of span is used!!!
|
|
||||||
int32_t max_f = q_span, n_skip = 0, min_d;
|
|
||||||
int32_t sidi = (a[i].y & MM_SEED_SEG_MASK) >> MM_SEED_SEG_SHIFT;
|
|
||||||
while (st < i && ri > a[st].x + max_dist_x) ++st;
|
|
||||||
for (j = i - 1; j >= st; --j) {
|
|
||||||
int64_t dr = ri - a[j].x;
|
|
||||||
int32_t dq = qi - (int32_t)a[j].y, dd, sc, log_dd;
|
|
||||||
int32_t sidj = (a[j].y & MM_SEED_SEG_MASK) >> MM_SEED_SEG_SHIFT;
|
|
||||||
if ((sidi == sidj && dr == 0) || dq <= 0) continue; // don't skip if an anchor is used by multiple segments; see below
|
|
||||||
if ((sidi == sidj && dq > max_dist_y) || dq > max_dist_x) continue;
|
|
||||||
dd = dr > dq? dr - dq : dq - dr;
|
|
||||||
if (sidi == sidj && dd > bw) continue;
|
|
||||||
if (n_segs > 1 && !is_cdna && sidi == sidj && dr > max_dist_y) continue;
|
|
||||||
min_d = dq < dr? dq : dr;
|
|
||||||
sc = min_d > q_span? q_span : dq < dr? dq : dr;
|
|
||||||
log_dd = dd? ilog2_32(dd) : 0;
|
|
||||||
if (is_cdna || sidi != sidj) {
|
|
||||||
int c_log, c_lin;
|
|
||||||
c_lin = (int)(dd * .01 * avg_qspan);
|
|
||||||
c_log = log_dd;
|
|
||||||
if (sidi != sidj && dr == 0) ++sc; // possibly due to overlapping paired ends; give a minor bonus
|
|
||||||
else if (dr > dq || sidi != sidj) sc -= c_lin < c_log? c_lin : c_log;
|
|
||||||
else sc -= c_lin + (c_log>>1);
|
|
||||||
} else sc -= (int)(dd * .01 * avg_qspan) + (log_dd>>1);
|
|
||||||
sc += f[j];
|
|
||||||
if (sc > max_f) {
|
|
||||||
max_f = sc, max_j = j;
|
|
||||||
if (n_skip > 0) --n_skip;
|
|
||||||
} else if (t[j] == i) {
|
|
||||||
if (++n_skip > max_skip)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p[j] >= 0) t[p[j]] = i;
|
|
||||||
}
|
|
||||||
f[i] = max_f, p[i] = max_j;
|
|
||||||
v[i] = max_j >= 0 && v[max_j] > max_f? v[max_j] : max_f; // v[] keeps the peak score up to i; f[] is the score ending at i, not always the peak
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the ending positions of chains
|
|
||||||
memset(t, 0, n * 4);
|
|
||||||
for (i = 0; i < n; ++i)
|
|
||||||
if (p[i] >= 0) t[p[i]] = 1;
|
|
||||||
for (i = n_u = 0; i < n; ++i)
|
|
||||||
if (t[i] == 0 && v[i] >= min_sc)
|
|
||||||
++n_u;
|
|
||||||
if (n_u == 0) {
|
|
||||||
kfree(km, a); kfree(km, f); kfree(km, p); kfree(km, t); kfree(km, v);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u = (uint64_t*)kmalloc(km, n_u * 8);
|
|
||||||
for (i = n_u = 0; i < n; ++i) {
|
|
||||||
if (t[i] == 0 && v[i] >= min_sc) {
|
|
||||||
j = i;
|
|
||||||
while (j >= 0 && f[j] < v[j]) j = p[j]; // find the peak that maximizes f[]
|
|
||||||
if (j < 0) j = i; // TODO: this should really be assert(j>=0)
|
|
||||||
u[n_u++] = (uint64_t)f[j] << 32 | j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
radix_sort_64(u, u + n_u);
|
|
||||||
for (i = 0; i < n_u>>1; ++i) { // reverse, s.t. the highest scoring chain is the first
|
|
||||||
uint64_t t = u[i];
|
|
||||||
u[i] = u[n_u - i - 1], u[n_u - i - 1] = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// backtrack
|
|
||||||
memset(t, 0, n * 4);
|
|
||||||
for (i = n_v = k = 0; i < n_u; ++i) { // starting from the highest score
|
|
||||||
int32_t n_v0 = n_v, k0 = k;
|
|
||||||
j = (int32_t)u[i];
|
|
||||||
do {
|
|
||||||
v[n_v++] = j;
|
|
||||||
t[j] = 1;
|
|
||||||
j = p[j];
|
|
||||||
} while (j >= 0 && t[j] == 0);
|
|
||||||
if (j < 0) {
|
|
||||||
if (n_v - n_v0 >= min_cnt) u[k++] = u[i]>>32<<32 | (n_v - n_v0);
|
|
||||||
} else if ((int32_t)(u[i]>>32) - f[j] >= min_sc) {
|
|
||||||
if (n_v - n_v0 >= min_cnt) u[k++] = ((u[i]>>32) - f[j]) << 32 | (n_v - n_v0);
|
|
||||||
}
|
|
||||||
if (k0 == k) n_v = n_v0; // no new chain added, reset
|
|
||||||
}
|
|
||||||
*n_u_ = n_u = k, *_u = u; // NB: note that u[] may not be sorted by score here
|
|
||||||
|
|
||||||
// free temporary arrays
|
|
||||||
kfree(km, f); kfree(km, p); kfree(km, t);
|
|
||||||
|
|
||||||
// write the result to b[]
|
|
||||||
b = (mm128_t*)kmalloc(km, n_v * sizeof(mm128_t));
|
|
||||||
for (i = 0, k = 0; i < n_u; ++i) {
|
|
||||||
int32_t k0 = k, ni = (int32_t)u[i];
|
|
||||||
for (j = 0; j < ni; ++j)
|
|
||||||
b[k] = a[v[k0 + (ni - j - 1)]], ++k;
|
|
||||||
}
|
|
||||||
kfree(km, v);
|
|
||||||
|
|
||||||
// sort u[] and a[] by a[].x, such that adjacent chains may be joined (required by mm_join_long)
|
|
||||||
w = (mm128_t*)kmalloc(km, n_u * sizeof(mm128_t));
|
|
||||||
for (i = k = 0; i < n_u; ++i) {
|
|
||||||
w[i].x = b[k].x, w[i].y = (uint64_t)k<<32|i;
|
|
||||||
k += (int32_t)u[i];
|
|
||||||
}
|
|
||||||
radix_sort_128x(w, w + n_u);
|
|
||||||
u2 = (uint64_t*)kmalloc(km, n_u * 8);
|
|
||||||
for (i = k = 0; i < n_u; ++i) {
|
|
||||||
int32_t j = (int32_t)w[i].y, n = (int32_t)u[j];
|
|
||||||
u2[i] = u[j];
|
|
||||||
memcpy(&a[k], &b[w[i].y>>32], n * sizeof(mm128_t));
|
|
||||||
k += n;
|
|
||||||
}
|
|
||||||
memcpy(u, u2, n_u * 8);
|
|
||||||
memcpy(b, a, k * sizeof(mm128_t)); // write _a_ to _b_ and deallocate _a_ because _a_ is oversized, sometimes a lot
|
|
||||||
kfree(km, a); kfree(km, w); kfree(km, u2);
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
## Contributor Code of Conduct
|
||||||
|
|
||||||
|
As contributors and maintainers of this project, we pledge to respect all
|
||||||
|
people who contribute through reporting issues, posting feature requests,
|
||||||
|
updating documentation, submitting pull requests or patches, and other
|
||||||
|
activities.
|
||||||
|
|
||||||
|
We are committed to making participation in this project a harassment-free
|
||||||
|
experience for everyone, regardless of level of experience, gender, gender
|
||||||
|
identity and expression, sexual orientation, disability, personal appearance,
|
||||||
|
body size, race, age, or religion.
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include the use of sexual
|
||||||
|
language or imagery, derogatory comments or personal attacks, trolling, public
|
||||||
|
or private harassment, insults, or other unprofessional conduct.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct. Project maintainers or
|
||||||
|
contributors who do not follow the Code of Conduct may be removed from the
|
||||||
|
project team.
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by opening an issue or contacting the maintainer via email.
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][cc], [version
|
||||||
|
1.0.0][v1].
|
||||||
|
|
||||||
|
[cc]: http://contributor-covenant.org/
|
||||||
|
[v1]: http://contributor-covenant.org/version/1/0/0/
|
||||||
+6
-6
@@ -31,8 +31,8 @@ To acquire the data used in this cookbook and to install minimap2 and paftools,
|
|||||||
please follow the command lines below:
|
please follow the command lines below:
|
||||||
```sh
|
```sh
|
||||||
# install minimap2 executables
|
# install minimap2 executables
|
||||||
curl -L https://github.com/lh3/minimap2/releases/download/v2.13/minimap2-2.13_x64-linux.tar.bz2 | tar jxf -
|
curl -L https://github.com/lh3/minimap2/releases/download/v2.22/minimap2-2.22_x64-linux.tar.bz2 | tar jxf -
|
||||||
cp minimap2-2.13_x64-linux/{minimap2,k8,paftools.js} . # copy executables
|
cp minimap2-2.22_x64-linux/{minimap2,k8,paftools.js} . # copy executables
|
||||||
export PATH="$PATH:"`pwd` # put the current directory on PATH
|
export PATH="$PATH:"`pwd` # put the current directory on PATH
|
||||||
# download example datasets
|
# download example datasets
|
||||||
curl -L https://github.com/lh3/minimap2/releases/download/v2.10/cookbook-data.tgz | tar zxf -
|
curl -L https://github.com/lh3/minimap2/releases/download/v2.10/cookbook-data.tgz | tar zxf -
|
||||||
@@ -80,12 +80,12 @@ where a `U`-line gives the number of unmapped reads (for SAM input only); a
|
|||||||
5. Accumulative number of mappings
|
5. Accumulative number of mappings
|
||||||
|
|
||||||
For `paftools.js mapeval` to work, you need to encode the true read positions
|
For `paftools.js mapeval` to work, you need to encode the true read positions
|
||||||
in read names in the right format. For [PBSIM][pbsim] and [mason2][mason2], we
|
in read names in the right format. For [pbsim2][pbsim] and [mason2][mason2], we
|
||||||
provide scripts to generate the right format. Simulated reads in this cookbook
|
provide scripts to generate the right format. Simulated reads in this cookbook
|
||||||
were created with the following command lines:
|
were created with the following command lines:
|
||||||
```sh
|
```sh
|
||||||
# in PBSIM source code directory:
|
# in the pbsim2 source code directory:
|
||||||
src/pbsim ../ecoli_ref.fa --depth 1 --sample-fastq sample/sample.fastq
|
src/pbsim --depth 1 --length-min 5000 --length-mean 20000 --accuracy-mean 0.95 --hmm_model data/R94.model ../ecoli_ref.fa
|
||||||
paftools.js pbsim2fq ../ecoli_ref.fa.fai sd_0001.maf > ../ecoli_pbsim.fa
|
paftools.js pbsim2fq ../ecoli_ref.fa.fai sd_0001.maf > ../ecoli_pbsim.fa
|
||||||
|
|
||||||
# mason2 simulation
|
# mason2 simulation
|
||||||
@@ -237,7 +237,7 @@ with `-x ava-pb` (99% vs 93% with `-x ava-ont`).
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[pbsim]: https://github.com/pfaucon/PBSIM-PacBio-Simulator
|
[pbsim]: https://github.com/yukiteruono/pbsim2
|
||||||
[mason2]: https://github.com/seqan/seqan/tree/master/apps/mason2
|
[mason2]: https://github.com/seqan/seqan/tree/master/apps/mason2
|
||||||
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
|
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
|
||||||
[v2.10]: https://github.com/lh3/minimap2/releases/tag/v2.10
|
[v2.10]: https://github.com/lh3/minimap2/releases/tag/v2.10
|
||||||
|
|||||||
@@ -59,6 +59,6 @@ void mm_est_err(const mm_idx_t *mi, int qlen, int n_regs, mm_reg1_t *regs, const
|
|||||||
n_tot = en - st + 1;
|
n_tot = en - st + 1;
|
||||||
if (r->qs > avg_k && r->rs > avg_k) ++n_tot;
|
if (r->qs > avg_k && r->rs > avg_k) ++n_tot;
|
||||||
if (qlen - r->qs > avg_k && l_ref - r->re > avg_k) ++n_tot;
|
if (qlen - r->qs > avg_k && l_ref - r->re > avg_k) ++n_tot;
|
||||||
r->div = logf((float)n_tot / n_match) / avg_k;
|
r->div = n_match >= n_tot? 0.0f : (float)(1.0 - pow((double)n_match / n_tot, 1.0 / avg_k));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ int main(int argc, char *argv[])
|
|||||||
while ((mi = mm_idx_reader_read(r, n_threads)) != 0) { // traverse each part of the index
|
while ((mi = mm_idx_reader_read(r, n_threads)) != 0) { // traverse each part of the index
|
||||||
mm_mapopt_update(&mopt, mi); // this sets the maximum minimizer occurrence; TODO: set a better default in mm_mapopt_init()!
|
mm_mapopt_update(&mopt, mi); // this sets the maximum minimizer occurrence; TODO: set a better default in mm_mapopt_init()!
|
||||||
mm_tbuf_t *tbuf = mm_tbuf_init(); // thread buffer; for multi-threading, allocate one tbuf for each thread
|
mm_tbuf_t *tbuf = mm_tbuf_init(); // thread buffer; for multi-threading, allocate one tbuf for each thread
|
||||||
|
gzrewind(f);
|
||||||
|
kseq_rewind(ks);
|
||||||
while (kseq_read(ks) >= 0) { // each kseq_read() call reads one query sequence
|
while (kseq_read(ks) >= 0) { // each kseq_read() call reads one query sequence
|
||||||
mm_reg1_t *reg;
|
mm_reg1_t *reg;
|
||||||
int j, i, n_reg;
|
int j, i, n_reg;
|
||||||
@@ -45,7 +47,7 @@ int main(int argc, char *argv[])
|
|||||||
printf("%s\t%d\t%d\t%d\t%c\t", ks->name.s, ks->seq.l, r->qs, r->qe, "+-"[r->rev]);
|
printf("%s\t%d\t%d\t%d\t%c\t", ks->name.s, ks->seq.l, r->qs, r->qe, "+-"[r->rev]);
|
||||||
printf("%s\t%d\t%d\t%d\t%d\t%d\t%d\tcg:Z:", mi->seq[r->rid].name, mi->seq[r->rid].len, r->rs, r->re, r->mlen, r->blen, r->mapq);
|
printf("%s\t%d\t%d\t%d\t%d\t%d\t%d\tcg:Z:", mi->seq[r->rid].name, mi->seq[r->rid].len, r->rs, r->re, r->mlen, r->blen, r->mapq);
|
||||||
for (i = 0; i < r->p->n_cigar; ++i) // IMPORTANT: this gives the CIGAR in the aligned regions. NO soft/hard clippings!
|
for (i = 0; i < r->p->n_cigar; ++i) // IMPORTANT: this gives the CIGAR in the aligned regions. NO soft/hard clippings!
|
||||||
printf("%d%c", r->p->cigar[i]>>4, "MIDSHN"[r->p->cigar[i]&0xf]);
|
printf("%d%c", r->p->cigar[i]>>4, MM_CIGAR_STR[r->p->cigar[i]&0xf]);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
free(r->p);
|
free(r->p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,11 +79,11 @@ static char *mm_escape(char *s)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sam_write_rg_line(kstring_t *str, const char *s)
|
static int sam_write_rg_line(kstring_t *str, const char *s)
|
||||||
{
|
{
|
||||||
char *p, *q, *r, *rg_line = 0;
|
char *p, *q, *r, *rg_line = 0;
|
||||||
memset(mm_rg_id, 0, 256);
|
memset(mm_rg_id, 0, 256);
|
||||||
if (s == 0) return;
|
if (s == 0) return 0;
|
||||||
if (strstr(s, "@RG") != s) {
|
if (strstr(s, "@RG") != s) {
|
||||||
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line is not started with @RG\n");
|
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line is not started with @RG\n");
|
||||||
goto err_set_rg;
|
goto err_set_rg;
|
||||||
@@ -92,7 +92,8 @@ static void sam_write_rg_line(kstring_t *str, const char *s)
|
|||||||
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line contained literal <tab> characters -- replace with escaped tabs: \\t\n");
|
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line contained literal <tab> characters -- replace with escaped tabs: \\t\n");
|
||||||
goto err_set_rg;
|
goto err_set_rg;
|
||||||
}
|
}
|
||||||
rg_line = strdup(s);
|
rg_line = (char*)malloc(strlen(s) + 1);
|
||||||
|
strcpy(rg_line, s);
|
||||||
mm_escape(rg_line);
|
mm_escape(rg_line);
|
||||||
if ((p = strstr(rg_line, "\tID:")) == 0) {
|
if ((p = strstr(rg_line, "\tID:")) == 0) {
|
||||||
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] no ID within the read group line\n");
|
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] no ID within the read group line\n");
|
||||||
@@ -107,20 +108,23 @@ static void sam_write_rg_line(kstring_t *str, const char *s)
|
|||||||
for (q = p, r = mm_rg_id; *q && *q != '\t' && *q != '\n'; ++q)
|
for (q = p, r = mm_rg_id; *q && *q != '\t' && *q != '\n'; ++q)
|
||||||
*r++ = *q;
|
*r++ = *q;
|
||||||
mm_sprintf_lite(str, "%s\n", rg_line);
|
mm_sprintf_lite(str, "%s\n", rg_line);
|
||||||
|
return 0;
|
||||||
|
|
||||||
err_set_rg:
|
err_set_rg:
|
||||||
free(rg_line);
|
free(rg_line);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int argc, char *argv[])
|
int mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int argc, char *argv[])
|
||||||
{
|
{
|
||||||
kstring_t str = {0,0,0};
|
kstring_t str = {0,0,0};
|
||||||
|
int ret = 0;
|
||||||
if (idx) {
|
if (idx) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i = 0; i < idx->n_seq; ++i)
|
for (i = 0; i < idx->n_seq; ++i)
|
||||||
mm_sprintf_lite(&str, "@SQ\tSN:%s\tLN:%d\n", idx->seq[i].name, idx->seq[i].len);
|
mm_sprintf_lite(&str, "@SQ\tSN:%s\tLN:%d\n", idx->seq[i].name, idx->seq[i].len);
|
||||||
}
|
}
|
||||||
if (rg) sam_write_rg_line(&str, rg);
|
if (rg) ret = sam_write_rg_line(&str, rg);
|
||||||
mm_sprintf_lite(&str, "@PG\tID:minimap2\tPN:minimap2");
|
mm_sprintf_lite(&str, "@PG\tID:minimap2\tPN:minimap2");
|
||||||
if (ver) mm_sprintf_lite(&str, "\tVN:%s", ver);
|
if (ver) mm_sprintf_lite(&str, "\tVN:%s", ver);
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@@ -131,6 +135,7 @@ void mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int
|
|||||||
}
|
}
|
||||||
mm_err_puts(str.s);
|
mm_err_puts(str.s);
|
||||||
free(str.s);
|
free(str.s);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_cs_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mm_reg1_t *r, char *tmp, int no_iden, int write_tag)
|
static void write_cs_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mm_reg1_t *r, char *tmp, int no_iden, int write_tag)
|
||||||
@@ -139,8 +144,8 @@ static void write_cs_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
|
|||||||
if (write_tag) mm_sprintf_lite(s, "\tcs:Z:");
|
if (write_tag) mm_sprintf_lite(s, "\tcs:Z:");
|
||||||
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
||||||
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
||||||
assert(op >= 0 && op <= 3);
|
assert((op >= MM_CIGAR_MATCH && op <= MM_CIGAR_N_SKIP) || op == MM_CIGAR_EQ_MATCH || op == MM_CIGAR_X_MISMATCH);
|
||||||
if (op == 0) { // match
|
if (op == MM_CIGAR_MATCH || op == MM_CIGAR_EQ_MATCH || op == MM_CIGAR_X_MISMATCH) {
|
||||||
int l_tmp = 0;
|
int l_tmp = 0;
|
||||||
for (j = 0; j < len; ++j) {
|
for (j = 0; j < len; ++j) {
|
||||||
if (qseq[q_off + j] != tseq[t_off + j]) {
|
if (qseq[q_off + j] != tseq[t_off + j]) {
|
||||||
@@ -161,12 +166,12 @@ static void write_cs_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
|
|||||||
} else mm_sprintf_lite(s, ":%d", l_tmp);
|
} else mm_sprintf_lite(s, ":%d", l_tmp);
|
||||||
}
|
}
|
||||||
q_off += len, t_off += len;
|
q_off += len, t_off += len;
|
||||||
} else if (op == 1) { // insertion to ref
|
} else if (op == MM_CIGAR_INS) {
|
||||||
for (j = 0, tmp[len] = 0; j < len; ++j)
|
for (j = 0, tmp[len] = 0; j < len; ++j)
|
||||||
tmp[j] = "acgtn"[qseq[q_off + j]];
|
tmp[j] = "acgtn"[qseq[q_off + j]];
|
||||||
mm_sprintf_lite(s, "+%s", tmp);
|
mm_sprintf_lite(s, "+%s", tmp);
|
||||||
q_off += len;
|
q_off += len;
|
||||||
} else if (op == 2) { // deletion from ref
|
} else if (op == MM_CIGAR_DEL) {
|
||||||
for (j = 0, tmp[len] = 0; j < len; ++j)
|
for (j = 0, tmp[len] = 0; j < len; ++j)
|
||||||
tmp[j] = "acgtn"[tseq[t_off + j]];
|
tmp[j] = "acgtn"[tseq[t_off + j]];
|
||||||
mm_sprintf_lite(s, "-%s", tmp);
|
mm_sprintf_lite(s, "-%s", tmp);
|
||||||
@@ -187,8 +192,8 @@ static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
|
|||||||
if (write_tag) mm_sprintf_lite(s, "\tMD:Z:");
|
if (write_tag) mm_sprintf_lite(s, "\tMD:Z:");
|
||||||
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
for (i = q_off = t_off = 0; i < (int)r->p->n_cigar; ++i) {
|
||||||
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
|
||||||
assert(op >= 0 && op <= 3);
|
assert((op >= MM_CIGAR_MATCH && op <= MM_CIGAR_N_SKIP) || op == MM_CIGAR_EQ_MATCH || op == MM_CIGAR_X_MISMATCH);
|
||||||
if (op == 0) { // match
|
if (op == MM_CIGAR_MATCH || op == MM_CIGAR_EQ_MATCH || op == MM_CIGAR_X_MISMATCH) {
|
||||||
for (j = 0; j < len; ++j) {
|
for (j = 0; j < len; ++j) {
|
||||||
if (qseq[q_off + j] != tseq[t_off + j]) {
|
if (qseq[q_off + j] != tseq[t_off + j]) {
|
||||||
mm_sprintf_lite(s, "%d%c", l_MD, "ACGTN"[tseq[t_off + j]]);
|
mm_sprintf_lite(s, "%d%c", l_MD, "ACGTN"[tseq[t_off + j]]);
|
||||||
@@ -196,15 +201,15 @@ static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
|
|||||||
} else ++l_MD;
|
} else ++l_MD;
|
||||||
}
|
}
|
||||||
q_off += len, t_off += len;
|
q_off += len, t_off += len;
|
||||||
} else if (op == 1) { // insertion to ref
|
} else if (op == MM_CIGAR_INS) {
|
||||||
q_off += len;
|
q_off += len;
|
||||||
} else if (op == 2) { // deletion from ref
|
} else if (op == MM_CIGAR_DEL) {
|
||||||
for (j = 0, tmp[len] = 0; j < len; ++j)
|
for (j = 0, tmp[len] = 0; j < len; ++j)
|
||||||
tmp[j] = "ACGTN"[tseq[t_off + j]];
|
tmp[j] = "ACGTN"[tseq[t_off + j]];
|
||||||
mm_sprintf_lite(s, "%d^%s", l_MD, tmp);
|
mm_sprintf_lite(s, "%d^%s", l_MD, tmp);
|
||||||
l_MD = 0;
|
l_MD = 0;
|
||||||
t_off += len;
|
t_off += len;
|
||||||
} else if (op == 3) { // reference skip
|
} else if (op == MM_CIGAR_N_SKIP) {
|
||||||
t_off += len;
|
t_off += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,7 +217,7 @@ static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
|
|||||||
assert(t_off == r->re - r->rs && q_off == r->qe - r->qs);
|
assert(t_off == r->re - r->rs && q_off == r->qe - r->qs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_cs_or_MD(void *km, kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int no_iden, int is_MD, int write_tag)
|
static void write_cs_or_MD(void *km, kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int no_iden, int is_MD, int write_tag, int is_qstrand)
|
||||||
{
|
{
|
||||||
extern unsigned char seq_nt4_table[256];
|
extern unsigned char seq_nt4_table[256];
|
||||||
int i;
|
int i;
|
||||||
@@ -222,14 +227,20 @@ static void write_cs_or_MD(void *km, kstring_t *s, const mm_idx_t *mi, const mm_
|
|||||||
qseq = (uint8_t*)kmalloc(km, r->qe - r->qs);
|
qseq = (uint8_t*)kmalloc(km, r->qe - r->qs);
|
||||||
tseq = (uint8_t*)kmalloc(km, r->re - r->rs);
|
tseq = (uint8_t*)kmalloc(km, r->re - r->rs);
|
||||||
tmp = (char*)kmalloc(km, r->re - r->rs > r->qe - r->qs? r->re - r->rs + 1 : r->qe - r->qs + 1);
|
tmp = (char*)kmalloc(km, r->re - r->rs > r->qe - r->qs? r->re - r->rs + 1 : r->qe - r->qs + 1);
|
||||||
mm_idx_getseq(mi, r->rid, r->rs, r->re, tseq);
|
if (is_qstrand) {
|
||||||
if (!r->rev) {
|
mm_idx_getseq2(mi, r->rev, r->rid, r->rs, r->re, tseq);
|
||||||
for (i = r->qs; i < r->qe; ++i)
|
for (i = r->qs; i < r->qe; ++i)
|
||||||
qseq[i - r->qs] = seq_nt4_table[(uint8_t)t->seq[i]];
|
qseq[i - r->qs] = seq_nt4_table[(uint8_t)t->seq[i]];
|
||||||
} else {
|
} else {
|
||||||
for (i = r->qs; i < r->qe; ++i) {
|
mm_idx_getseq(mi, r->rid, r->rs, r->re, tseq);
|
||||||
uint8_t c = seq_nt4_table[(uint8_t)t->seq[i]];
|
if (!r->rev) {
|
||||||
qseq[r->qe - i - 1] = c >= 4? 4 : 3 - c;
|
for (i = r->qs; i < r->qe; ++i)
|
||||||
|
qseq[i - r->qs] = seq_nt4_table[(uint8_t)t->seq[i]];
|
||||||
|
} else {
|
||||||
|
for (i = r->qs; i < r->qe; ++i) {
|
||||||
|
uint8_t c = seq_nt4_table[(uint8_t)t->seq[i]];
|
||||||
|
qseq[r->qe - i - 1] = c >= 4? 4 : 3 - c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (is_MD) write_MD_core(s, tseq, qseq, r, tmp, write_tag);
|
if (is_MD) write_MD_core(s, tseq, qseq, r, tmp, write_tag);
|
||||||
@@ -237,14 +248,14 @@ static void write_cs_or_MD(void *km, kstring_t *s, const mm_idx_t *mi, const mm_
|
|||||||
kfree(km, qseq); kfree(km, tseq); kfree(km, tmp);
|
kfree(km, qseq); kfree(km, tseq); kfree(km, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_gen_cs_or_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq, int is_MD, int no_iden)
|
int mm_gen_cs_or_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq, int is_MD, int no_iden, int is_qstrand)
|
||||||
{
|
{
|
||||||
mm_bseq1_t t;
|
mm_bseq1_t t;
|
||||||
kstring_t str;
|
kstring_t str;
|
||||||
str.s = *buf, str.l = 0, str.m = *max_len;
|
str.s = *buf, str.l = 0, str.m = *max_len;
|
||||||
t.l_seq = strlen(seq);
|
t.l_seq = strlen(seq);
|
||||||
t.seq = (char*)seq;
|
t.seq = (char*)seq;
|
||||||
write_cs_or_MD(km, &str, mi, &t, r, no_iden, is_MD, 0);
|
write_cs_or_MD(km, &str, mi, &t, r, no_iden, is_MD, 0, is_qstrand);
|
||||||
*max_len = str.m;
|
*max_len = str.m;
|
||||||
*buf = str.s;
|
*buf = str.s;
|
||||||
return str.l;
|
return str.l;
|
||||||
@@ -252,12 +263,12 @@ int mm_gen_cs_or_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, cons
|
|||||||
|
|
||||||
int mm_gen_cs(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq, int no_iden)
|
int mm_gen_cs(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq, int no_iden)
|
||||||
{
|
{
|
||||||
return mm_gen_cs_or_MD(km, buf, max_len, mi, r, seq, 0, no_iden);
|
return mm_gen_cs_or_MD(km, buf, max_len, mi, r, seq, 0, no_iden, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_gen_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq)
|
int mm_gen_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq)
|
||||||
{
|
{
|
||||||
return mm_gen_cs_or_MD(km, buf, max_len, mi, r, seq, 1, 0);
|
return mm_gen_cs_or_MD(km, buf, max_len, mi, r, seq, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
|
static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
|
||||||
@@ -272,41 +283,59 @@ static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
|
|||||||
}
|
}
|
||||||
mm_sprintf_lite(s, "\ttp:A:%c\tcm:i:%d\ts1:i:%d", type, r->cnt, r->score);
|
mm_sprintf_lite(s, "\ttp:A:%c\tcm:i:%d\ts1:i:%d", type, r->cnt, r->score);
|
||||||
if (r->parent == r->id) mm_sprintf_lite(s, "\ts2:i:%d", r->subsc);
|
if (r->parent == r->id) mm_sprintf_lite(s, "\ts2:i:%d", r->subsc);
|
||||||
if (r->div >= 0.0f && r->div <= 1.0f) {
|
if (r->p) {
|
||||||
char buf[8];
|
char buf[16];
|
||||||
|
double div;
|
||||||
|
div = 1.0 - mm_event_identity(r);
|
||||||
|
if (div == 0.0) buf[0] = '0', buf[1] = 0;
|
||||||
|
else snprintf(buf, 16, "%.4f", 1.0 - mm_event_identity(r));
|
||||||
|
mm_sprintf_lite(s, "\tde:f:%s", buf);
|
||||||
|
} else if (r->div >= 0.0f && r->div <= 1.0f) {
|
||||||
|
char buf[16];
|
||||||
if (r->div == 0.0f) buf[0] = '0', buf[1] = 0;
|
if (r->div == 0.0f) buf[0] = '0', buf[1] = 0;
|
||||||
else sprintf(buf, "%.4f", r->div);
|
else snprintf(buf, 16, "%.4f", r->div);
|
||||||
mm_sprintf_lite(s, "\tdv:f:%s", buf);
|
mm_sprintf_lite(s, "\tdv:f:%s", buf);
|
||||||
}
|
}
|
||||||
if (r->split) mm_sprintf_lite(s, "\tzd:i:%d", r->split);
|
if (r->split) mm_sprintf_lite(s, "\tzd:i:%d", r->split);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int opt_flag)
|
void mm_write_paf3(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int64_t opt_flag, int rep_len)
|
||||||
{
|
{
|
||||||
s->l = 0;
|
s->l = 0;
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
mm_sprintf_lite(s, "%s\t%d", t->name, t->l_seq);
|
mm_sprintf_lite(s, "%s\t%d\t0\t0\t*\t*\t0\t0\t0\t0\t0\t0", t->name, t->l_seq);
|
||||||
|
if (rep_len >= 0) mm_sprintf_lite(s, "\trl:i:%d", rep_len);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mm_sprintf_lite(s, "%s\t%d\t%d\t%d\t%c\t", t->name, t->l_seq, r->qs, r->qe, "+-"[r->rev]);
|
mm_sprintf_lite(s, "%s\t%d\t%d\t%d\t%c\t", t->name, t->l_seq, r->qs, r->qe, "+-"[r->rev]);
|
||||||
if (mi->seq[r->rid].name) mm_sprintf_lite(s, "%s", mi->seq[r->rid].name);
|
if (mi->seq[r->rid].name) mm_sprintf_lite(s, "%s", mi->seq[r->rid].name);
|
||||||
else mm_sprintf_lite(s, "%d", r->rid);
|
else mm_sprintf_lite(s, "%d", r->rid);
|
||||||
mm_sprintf_lite(s, "\t%d\t%d\t%d", mi->seq[r->rid].len, r->rs, r->re);
|
mm_sprintf_lite(s, "\t%d", mi->seq[r->rid].len);
|
||||||
|
if ((opt_flag & MM_F_QSTRAND) && r->rev)
|
||||||
|
mm_sprintf_lite(s, "\t%d\t%d", mi->seq[r->rid].len - r->re, mi->seq[r->rid].len - r->rs);
|
||||||
|
else
|
||||||
|
mm_sprintf_lite(s, "\t%d\t%d", r->rs, r->re);
|
||||||
mm_sprintf_lite(s, "\t%d\t%d", r->mlen, r->blen);
|
mm_sprintf_lite(s, "\t%d\t%d", r->mlen, r->blen);
|
||||||
mm_sprintf_lite(s, "\t%d", r->mapq);
|
mm_sprintf_lite(s, "\t%d", r->mapq);
|
||||||
write_tags(s, r);
|
write_tags(s, r);
|
||||||
|
if (rep_len >= 0) mm_sprintf_lite(s, "\trl:i:%d", rep_len);
|
||||||
if (r->p && (opt_flag & MM_F_OUT_CG)) {
|
if (r->p && (opt_flag & MM_F_OUT_CG)) {
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
mm_sprintf_lite(s, "\tcg:Z:");
|
mm_sprintf_lite(s, "\tcg:Z:");
|
||||||
for (k = 0; k < r->p->n_cigar; ++k)
|
for (k = 0; k < r->p->n_cigar; ++k)
|
||||||
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, "MIDNSHP=XB"[r->p->cigar[k]&0xf]);
|
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, MM_CIGAR_STR[r->p->cigar[k]&0xf]);
|
||||||
}
|
}
|
||||||
if (r->p && (opt_flag & (MM_F_OUT_CS|MM_F_OUT_MD)))
|
if (r->p && (opt_flag & (MM_F_OUT_CS|MM_F_OUT_MD)))
|
||||||
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&MM_F_OUT_MD, 1);
|
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&MM_F_OUT_MD, 1, !!(opt_flag&MM_F_QSTRAND));
|
||||||
if ((opt_flag & MM_F_COPY_COMMENT) && t->comment)
|
if ((opt_flag & MM_F_COPY_COMMENT) && t->comment)
|
||||||
mm_sprintf_lite(s, "\t%s", t->comment);
|
mm_sprintf_lite(s, "\t%s", t->comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int64_t opt_flag)
|
||||||
|
{
|
||||||
|
mm_write_paf3(s, mi, t, r, km, opt_flag, -1);
|
||||||
|
}
|
||||||
|
|
||||||
static void sam_write_sq(kstring_t *s, char *seq, int l, int rev, int comp)
|
static void sam_write_sq(kstring_t *s, char *seq, int l, int rev, int comp)
|
||||||
{
|
{
|
||||||
extern unsigned char seq_comp_table[256];
|
extern unsigned char seq_comp_table[256];
|
||||||
@@ -331,7 +360,7 @@ static inline const mm_reg1_t *get_sam_pri(int n_regs, const mm_reg1_t *regs)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, const mm_reg1_t *r, int opt_flag)
|
static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, const mm_reg1_t *r, int64_t opt_flag)
|
||||||
{
|
{
|
||||||
if (r->p == 0) {
|
if (r->p == 0) {
|
||||||
mm_sprintf_lite(s, "*");
|
mm_sprintf_lite(s, "*");
|
||||||
@@ -348,19 +377,20 @@ static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, co
|
|||||||
if (clip_len[1]) mm_sprintf_lite(s, ",%u", clip_len[1]<<4|clip_char);
|
if (clip_len[1]) mm_sprintf_lite(s, ",%u", clip_len[1]<<4|clip_char);
|
||||||
} else {
|
} else {
|
||||||
int clip_char = (sam_flag&0x800) && !(opt_flag&MM_F_SOFTCLIP)? 'H' : 'S';
|
int clip_char = (sam_flag&0x800) && !(opt_flag&MM_F_SOFTCLIP)? 'H' : 'S';
|
||||||
|
assert(clip_len[0] < qlen && clip_len[1] < qlen);
|
||||||
if (clip_len[0]) mm_sprintf_lite(s, "%d%c", clip_len[0], clip_char);
|
if (clip_len[0]) mm_sprintf_lite(s, "%d%c", clip_len[0], clip_char);
|
||||||
for (k = 0; k < r->p->n_cigar; ++k)
|
for (k = 0; k < r->p->n_cigar; ++k)
|
||||||
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, "MIDNSHP=XB"[r->p->cigar[k]&0xf]);
|
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, MM_CIGAR_STR[r->p->cigar[k]&0xf]);
|
||||||
if (clip_len[1]) mm_sprintf_lite(s, "%d%c", clip_len[1], clip_char);
|
if (clip_len[1]) mm_sprintf_lite(s, "%d%c", clip_len[1], clip_char);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regss, const mm_reg1_t *const* regss, void *km, int opt_flag)
|
void mm_write_sam3(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regss, const mm_reg1_t *const* regss, void *km, int64_t opt_flag, int rep_len)
|
||||||
{
|
{
|
||||||
const int max_bam_cigar_op = 65535;
|
const int max_bam_cigar_op = 65535;
|
||||||
int flag, n_regs = n_regss[seg_idx], cigar_in_tag = 0;
|
int flag, n_regs = n_regss[seg_idx], cigar_in_tag = 0;
|
||||||
int this_rid = -1, this_pos = -1, this_rev = 0;
|
int this_rid = -1, this_pos = -1;
|
||||||
const mm_reg1_t *regs = regss[seg_idx], *r_prev = NULL, *r_next;
|
const mm_reg1_t *regs = regss[seg_idx], *r_prev = NULL, *r_next;
|
||||||
const mm_reg1_t *r = n_regs > 0 && reg_idx < n_regs && reg_idx >= 0? ®s[reg_idx] : NULL;
|
const mm_reg1_t *r = n_regs > 0 && reg_idx < n_regs && reg_idx >= 0? ®s[reg_idx] : NULL;
|
||||||
|
|
||||||
@@ -409,7 +439,7 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
|
|||||||
mm_sprintf_lite(s, "\t%s\t%d\t0\t*", mi->seq[this_rid].name, this_pos+1);
|
mm_sprintf_lite(s, "\t%s\t%d\t0\t*", mi->seq[this_rid].name, this_pos+1);
|
||||||
} else mm_sprintf_lite(s, "\t*\t0\t0\t*");
|
} else mm_sprintf_lite(s, "\t*\t0\t0\t*");
|
||||||
} else {
|
} else {
|
||||||
this_rid = r->rid, this_pos = r->rs, this_rev = r->rev;
|
this_rid = r->rid, this_pos = r->rs;
|
||||||
mm_sprintf_lite(s, "\t%s\t%d\t%d\t", mi->seq[r->rid].name, r->rs+1, r->mapq);
|
mm_sprintf_lite(s, "\t%s\t%d\t%d\t", mi->seq[r->rid].name, r->rs+1, r->mapq);
|
||||||
if ((opt_flag & MM_F_LONG_CIGAR) && r->p && r->p->n_cigar > max_bam_cigar_op - 2) {
|
if ((opt_flag & MM_F_LONG_CIGAR) && r->p && r->p->n_cigar > max_bam_cigar_op - 2) {
|
||||||
int n_cigar = r->p->n_cigar;
|
int n_cigar = r->p->n_cigar;
|
||||||
@@ -432,17 +462,17 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
|
|||||||
int tlen = 0;
|
int tlen = 0;
|
||||||
if (this_rid >= 0 && r_next) {
|
if (this_rid >= 0 && r_next) {
|
||||||
if (this_rid == r_next->rid) {
|
if (this_rid == r_next->rid) {
|
||||||
int this_pos5 = r && r->rev? r->re - 1 : this_pos;
|
if (r) {
|
||||||
int next_pos5 = r_next->rev? r_next->re - 1 : r_next->rs;
|
int this_pos5 = r->rev? r->re - 1 : this_pos;
|
||||||
tlen = next_pos5 - this_pos5;
|
int next_pos5 = r_next->rev? r_next->re - 1 : r_next->rs;
|
||||||
|
tlen = next_pos5 - this_pos5;
|
||||||
|
}
|
||||||
mm_sprintf_lite(s, "\t=\t");
|
mm_sprintf_lite(s, "\t=\t");
|
||||||
} else mm_sprintf_lite(s, "\t%s\t", mi->seq[r_next->rid].name);
|
} else mm_sprintf_lite(s, "\t%s\t", mi->seq[r_next->rid].name);
|
||||||
mm_sprintf_lite(s, "%d\t", r_next->rs + 1);
|
mm_sprintf_lite(s, "%d\t", r_next->rs + 1);
|
||||||
} else if (r_next) { // && this_rid < 0
|
} else if (r_next) { // && this_rid < 0
|
||||||
mm_sprintf_lite(s, "\t%s\t%d\t", mi->seq[r_next->rid].name, r_next->rs + 1);
|
mm_sprintf_lite(s, "\t%s\t%d\t", mi->seq[r_next->rid].name, r_next->rs + 1);
|
||||||
} else if (this_rid >= 0) { // && r_next == NULL
|
} else if (this_rid >= 0) { // && r_next == NULL
|
||||||
int this_pos5 = this_rev? r->re - 1 : this_pos; // this_rev is only true when r != NULL
|
|
||||||
tlen = this_pos - this_pos5; // next_pos5 will be this_pos
|
|
||||||
mm_sprintf_lite(s, "\t=\t%d\t", this_pos + 1); // next segment will take r's coordinate
|
mm_sprintf_lite(s, "\t=\t%d\t", this_pos + 1); // next segment will take r's coordinate
|
||||||
} else mm_sprintf_lite(s, "\t*\t0\t"); // neither has coordinates
|
} else mm_sprintf_lite(s, "\t*\t0\t"); // neither has coordinates
|
||||||
if (tlen > 0) ++tlen;
|
if (tlen > 0) ++tlen;
|
||||||
@@ -503,10 +533,11 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (r->p && (opt_flag & (MM_F_OUT_CS|MM_F_OUT_MD)))
|
if (r->p && (opt_flag & (MM_F_OUT_CS|MM_F_OUT_MD)))
|
||||||
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&MM_F_OUT_MD, 1);
|
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&MM_F_OUT_MD, 1, 0);
|
||||||
if (cigar_in_tag)
|
if (cigar_in_tag)
|
||||||
write_sam_cigar(s, flag, 1, t->l_seq, r, opt_flag);
|
write_sam_cigar(s, flag, 1, t->l_seq, r, opt_flag);
|
||||||
}
|
}
|
||||||
|
if (rep_len >= 0) mm_sprintf_lite(s, "\trl:i:%d", rep_len);
|
||||||
|
|
||||||
if ((opt_flag & MM_F_COPY_COMMENT) && t->comment)
|
if ((opt_flag & MM_F_COPY_COMMENT) && t->comment)
|
||||||
mm_sprintf_lite(s, "\t%s", t->comment);
|
mm_sprintf_lite(s, "\t%s", t->comment);
|
||||||
@@ -514,6 +545,11 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
|
|||||||
s->s[s->l] = 0; // we always have room for an extra byte (see str_enlarge)
|
s->s[s->l] = 0; // we always have room for an extra byte (see str_enlarge)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regss, const mm_reg1_t *const* regss, void *km, int64_t opt_flag)
|
||||||
|
{
|
||||||
|
mm_write_sam3(s, mi, t, seg_idx, reg_idx, n_seg, n_regss, regss, km, opt_flag, -1);
|
||||||
|
}
|
||||||
|
|
||||||
void mm_write_sam(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int n_regs, const mm_reg1_t *regs)
|
void mm_write_sam(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int n_regs, const mm_reg1_t *regs)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ static inline void mm_cal_fuzzy_len(mm_reg1_t *r, const mm128_t *a)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mm_reg_set_coor(mm_reg1_t *r, int32_t qlen, const mm128_t *a)
|
static inline void mm_reg_set_coor(mm_reg1_t *r, int32_t qlen, const mm128_t *a, int is_qstrand)
|
||||||
{ // NB: r->as and r->cnt MUST BE set correctly for this function to work
|
{ // NB: r->as and r->cnt MUST BE set correctly for this function to work
|
||||||
int32_t k = r->as, q_span = (int32_t)(a[k].y>>32&0xff);
|
int32_t k = r->as, q_span = (int32_t)(a[k].y>>32&0xff);
|
||||||
r->rev = a[k].x>>63;
|
r->rev = a[k].x>>63;
|
||||||
r->rid = a[k].x<<1>>33;
|
r->rid = a[k].x<<1>>33;
|
||||||
r->rs = (int32_t)a[k].x + 1 > q_span? (int32_t)a[k].x + 1 - q_span : 0; // NB: target span may be shorter, so this test is necessary
|
r->rs = (int32_t)a[k].x + 1 > q_span? (int32_t)a[k].x + 1 - q_span : 0; // NB: target span may be shorter, so this test is necessary
|
||||||
r->re = (int32_t)a[k + r->cnt - 1].x + 1;
|
r->re = (int32_t)a[k + r->cnt - 1].x + 1;
|
||||||
if (!r->rev) {
|
if (!r->rev || is_qstrand) {
|
||||||
r->qs = (int32_t)a[k].y + 1 - q_span;
|
r->qs = (int32_t)a[k].y + 1 - q_span;
|
||||||
r->qe = (int32_t)a[k + r->cnt - 1].y + 1;
|
r->qe = (int32_t)a[k + r->cnt - 1].y + 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -49,7 +49,7 @@ static inline uint64_t hash64(uint64_t key)
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a) // convert chains to hits
|
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a, int is_qstrand) // convert chains to hits
|
||||||
{
|
{
|
||||||
mm128_t *z, tmp;
|
mm128_t *z, tmp;
|
||||||
mm_reg1_t *r;
|
mm_reg1_t *r;
|
||||||
@@ -81,13 +81,29 @@ mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u,
|
|||||||
ri->cnt = (int32_t)z[i].y;
|
ri->cnt = (int32_t)z[i].y;
|
||||||
ri->as = z[i].y >> 32;
|
ri->as = z[i].y >> 32;
|
||||||
ri->div = -1.0f;
|
ri->div = -1.0f;
|
||||||
mm_reg_set_coor(ri, qlen, a);
|
mm_reg_set_coor(ri, qlen, a, is_qstrand);
|
||||||
}
|
}
|
||||||
kfree(km, z);
|
kfree(km, z);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a)
|
void mm_mark_alt(const mm_idx_t *mi, int n, mm_reg1_t *r)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (mi->n_alt == 0) return;
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
if (mi->seq[r[i].rid].is_alt)
|
||||||
|
r[i].is_alt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mm_alt_score(int score, float alt_diff_frac)
|
||||||
|
{
|
||||||
|
if (score < 0) return score;
|
||||||
|
score = (int)(score * (1.0 - alt_diff_frac) + .499);
|
||||||
|
return score > 0? score : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a, int is_qstrand)
|
||||||
{
|
{
|
||||||
if (n <= 0 || n >= r->cnt) return;
|
if (n <= 0 || n >= r->cnt) return;
|
||||||
*r2 = *r;
|
*r2 = *r;
|
||||||
@@ -99,14 +115,14 @@ void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a)
|
|||||||
r2->score = (int32_t)(r->score * ((float)r2->cnt / r->cnt) + .499);
|
r2->score = (int32_t)(r->score * ((float)r2->cnt / r->cnt) + .499);
|
||||||
r2->as = r->as + n;
|
r2->as = r->as + n;
|
||||||
if (r->parent == r->id) r2->parent = MM_PARENT_TMP_PRI;
|
if (r->parent == r->id) r2->parent = MM_PARENT_TMP_PRI;
|
||||||
mm_reg_set_coor(r2, qlen, a);
|
mm_reg_set_coor(r2, qlen, a, is_qstrand);
|
||||||
r->cnt -= r2->cnt;
|
r->cnt -= r2->cnt;
|
||||||
r->score -= r2->score;
|
r->score -= r2->score;
|
||||||
mm_reg_set_coor(r, qlen, a);
|
mm_reg_set_coor(r, qlen, a, is_qstrand);
|
||||||
r->split |= 1, r2->split |= 2;
|
r->split |= 1, r2->split |= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level) // and compute mm_reg1_t::subsc
|
void mm_set_parent(void *km, float mask_level, int mask_len, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level, float alt_diff_frac) // and compute mm_reg1_t::subsc
|
||||||
{
|
{
|
||||||
int i, j, k, *w;
|
int i, j, k, *w;
|
||||||
uint64_t *cov;
|
uint64_t *cov;
|
||||||
@@ -146,13 +162,16 @@ skip_uncov:
|
|||||||
min = ej - sj < ei - si? ej - sj : ei - si;
|
min = ej - sj < ei - si? ej - sj : ei - si;
|
||||||
max = ej - sj > ei - si? ej - sj : ei - si;
|
max = ej - sj > ei - si? ej - sj : ei - si;
|
||||||
ol = si < sj? (ei < sj? 0 : ei < ej? ei - sj : ej - sj) : (ej < si? 0 : ej < ei? ej - si : ei - si); // overlap length; TODO: this can be simplified
|
ol = si < sj? (ei < sj? 0 : ei < ej? ei - sj : ej - sj) : (ej < si? 0 : ej < ei? ej - si : ei - si); // overlap length; TODO: this can be simplified
|
||||||
if ((float)ol / min - (float)uncov_len / max > mask_level) {
|
if ((float)ol / min - (float)uncov_len / max > mask_level && uncov_len <= mask_len) { // then this is a secondary hit
|
||||||
int cnt_sub = 0;
|
int cnt_sub = 0, sci = ri->score;
|
||||||
ri->parent = rp->parent;
|
ri->parent = rp->parent;
|
||||||
rp->subsc = rp->subsc > ri->score? rp->subsc : ri->score;
|
if (!rp->is_alt && ri->is_alt) sci = mm_alt_score(sci, alt_diff_frac);
|
||||||
|
rp->subsc = rp->subsc > sci? rp->subsc : sci;
|
||||||
if (ri->cnt >= rp->cnt) cnt_sub = 1;
|
if (ri->cnt >= rp->cnt) cnt_sub = 1;
|
||||||
if (rp->p && ri->p && (rp->rid != ri->rid || rp->rs != ri->rs || rp->re != ri->re || ol != min)) { // the last condition excludes identical hits after DP
|
if (rp->p && ri->p && (rp->rid != ri->rid || rp->rs != ri->rs || rp->re != ri->re || ol != min)) { // the last condition excludes identical hits after DP
|
||||||
rp->p->dp_max2 = rp->p->dp_max2 > ri->p->dp_max? rp->p->dp_max2 : ri->p->dp_max;
|
sci = ri->p->dp_max;
|
||||||
|
if (!rp->is_alt && ri->is_alt) sci = mm_alt_score(sci, alt_diff_frac);
|
||||||
|
rp->p->dp_max2 = rp->p->dp_max2 > sci? rp->p->dp_max2 : sci;
|
||||||
if (rp->p->dp_max - ri->p->dp_max <= sub_diff) cnt_sub = 1;
|
if (rp->p->dp_max - ri->p->dp_max <= sub_diff) cnt_sub = 1;
|
||||||
}
|
}
|
||||||
if (cnt_sub) ++rp->n_sub;
|
if (cnt_sub) ++rp->n_sub;
|
||||||
@@ -166,7 +185,7 @@ set_parent_test:
|
|||||||
kfree(km, w);
|
kfree(km, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r)
|
void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r, float alt_diff_frac)
|
||||||
{
|
{
|
||||||
int32_t i, n_aux, n = *n_regs, has_cigar = 0, no_cigar = 0;
|
int32_t i, n_aux, n = *n_regs, has_cigar = 0, no_cigar = 0;
|
||||||
mm128_t *aux;
|
mm128_t *aux;
|
||||||
@@ -177,13 +196,11 @@ void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r)
|
|||||||
t = (mm_reg1_t*)kmalloc(km, n * sizeof(mm_reg1_t));
|
t = (mm_reg1_t*)kmalloc(km, n * sizeof(mm_reg1_t));
|
||||||
for (i = n_aux = 0; i < n; ++i) {
|
for (i = n_aux = 0; i < n; ++i) {
|
||||||
if (r[i].inv || r[i].cnt > 0) { // squeeze out elements with cnt==0 (soft deleted)
|
if (r[i].inv || r[i].cnt > 0) { // squeeze out elements with cnt==0 (soft deleted)
|
||||||
if (r[i].p) {
|
int score;
|
||||||
aux[n_aux].x = (uint64_t)r[i].p->dp_max << 32 | r[i].hash;
|
if (r[i].p) score = r[i].p->dp_max, has_cigar = 1;
|
||||||
has_cigar = 1;
|
else score = r[i].score, no_cigar = 1;
|
||||||
} else {
|
if (r[i].is_alt) score = mm_alt_score(score, alt_diff_frac);
|
||||||
aux[n_aux].x = (uint64_t)r[i].score << 32 | r[i].hash;
|
aux[n_aux].x = (uint64_t)score << 32 | r[i].hash;
|
||||||
no_cigar = 1;
|
|
||||||
}
|
|
||||||
aux[n_aux++].y = i;
|
aux[n_aux++].y = i;
|
||||||
} else if (r[i].p) {
|
} else if (r[i].p) {
|
||||||
free(r[i].p);
|
free(r[i].p);
|
||||||
@@ -295,64 +312,6 @@ int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a)
|
|||||||
return as;
|
return as;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mm_join_long(void *km, const mm_mapopt_t *opt, int qlen, int *n_regs_, mm_reg1_t *regs, mm128_t *a)
|
|
||||||
{
|
|
||||||
int i, n_aux, n_regs = *n_regs_, n_drop = 0;
|
|
||||||
uint64_t *aux;
|
|
||||||
|
|
||||||
if (n_regs < 2) return; // nothing to join
|
|
||||||
mm_squeeze_a(km, n_regs, regs, a);
|
|
||||||
|
|
||||||
aux = (uint64_t*)kmalloc(km, n_regs * 8);
|
|
||||||
for (i = n_aux = 0; i < n_regs; ++i)
|
|
||||||
if (regs[i].parent == i || regs[i].parent < 0)
|
|
||||||
aux[n_aux++] = (uint64_t)regs[i].as << 32 | i;
|
|
||||||
radix_sort_64(aux, aux + n_aux);
|
|
||||||
|
|
||||||
for (i = n_aux - 1; i >= 1; --i) {
|
|
||||||
mm_reg1_t *r0 = ®s[(int32_t)aux[i-1]], *r1 = ®s[(int32_t)aux[i]];
|
|
||||||
mm128_t *a0e, *a1s;
|
|
||||||
int max_gap, min_gap, sc_thres, min_flank_len;
|
|
||||||
|
|
||||||
// test
|
|
||||||
if (r0->as + r0->cnt != r1->as) continue; // not adjacent in a[]
|
|
||||||
if (r0->rid != r1->rid || r0->rev != r1->rev) continue; // make sure on the same target and strand
|
|
||||||
a0e = &a[r0->as + r0->cnt - 1];
|
|
||||||
a1s = &a[r1->as];
|
|
||||||
if (a1s->x <= a0e->x || (int32_t)a1s->y <= (int32_t)a0e->y) continue; // keep colinearity
|
|
||||||
max_gap = min_gap = (int32_t)a1s->y - (int32_t)a0e->y;
|
|
||||||
max_gap = a0e->x + max_gap > a1s->x? max_gap : a1s->x - a0e->x;
|
|
||||||
min_gap = a0e->x + min_gap < a1s->x? min_gap : a1s->x - a0e->x;
|
|
||||||
if (max_gap > opt->max_join_long || min_gap > opt->max_join_short) continue;
|
|
||||||
sc_thres = (int)((float)opt->min_join_flank_sc / opt->max_join_long * max_gap + .499);
|
|
||||||
if (r0->score < sc_thres || r1->score < sc_thres) continue; // require good flanking chains
|
|
||||||
min_flank_len = (int)(max_gap * opt->min_join_flank_ratio);
|
|
||||||
if (r0->re - r0->rs < min_flank_len || r0->qe - r0->qs < min_flank_len) continue; // require enough flanking length
|
|
||||||
if (r1->re - r1->rs < min_flank_len || r1->qe - r1->qs < min_flank_len) continue;
|
|
||||||
|
|
||||||
// all conditions satisfied; join
|
|
||||||
a[r1->as].y |= MM_SEED_LONG_JOIN;
|
|
||||||
r0->cnt += r1->cnt, r0->score += r1->score;
|
|
||||||
mm_reg_set_coor(r0, qlen, a);
|
|
||||||
r1->cnt = 0;
|
|
||||||
r1->parent = r0->id;
|
|
||||||
++n_drop;
|
|
||||||
}
|
|
||||||
kfree(km, aux);
|
|
||||||
|
|
||||||
if (n_drop > 0) { // then fix the hits hierarchy
|
|
||||||
for (i = 0; i < n_regs; ++i) { // adjust the mm_reg1_t::parent
|
|
||||||
mm_reg1_t *r = ®s[i];
|
|
||||||
if (r->parent >= 0 && r->id != r->parent) { // fix for secondary hits only
|
|
||||||
if (regs[r->parent].parent >= 0 && regs[r->parent].parent != r->parent)
|
|
||||||
r->parent = regs[r->parent].parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mm_filter_regs(opt, qlen, n_regs_, regs);
|
|
||||||
mm_sync_regs(km, *n_regs_, regs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int n_regs0, const mm_reg1_t *regs0, int *n_regs, mm_reg1_t **regs, const mm128_t *a)
|
mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int n_regs0, const mm_reg1_t *regs0, int *n_regs, mm_reg1_t **regs, const mm128_t *a)
|
||||||
{
|
{
|
||||||
int s, i, j, acc_qlen[MM_MAX_SEG+1], qlen_sum = 0;
|
int s, i, j, acc_qlen[MM_MAX_SEG+1], qlen_sum = 0;
|
||||||
@@ -399,7 +358,7 @@ 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, 0);
|
||||||
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;
|
||||||
@@ -449,6 +408,7 @@ void mm_set_mapq(void *km, int n_regs, mm_reg1_t *regs, int min_chain_sc, int ma
|
|||||||
int64_t sum_sc = 0;
|
int64_t sum_sc = 0;
|
||||||
float uniq_ratio;
|
float uniq_ratio;
|
||||||
int i;
|
int i;
|
||||||
|
if (n_regs == 0) return;
|
||||||
for (i = 0; i < n_regs; ++i)
|
for (i = 0; i < n_regs; ++i)
|
||||||
if (regs[i].parent == regs[i].id)
|
if (regs[i].parent == regs[i].id)
|
||||||
sum_sc += regs[i].score;
|
sum_sc += regs[i].score;
|
||||||
|
|||||||
@@ -31,6 +31,16 @@ typedef struct mm_idx_bucket_s {
|
|||||||
void *h; // hash table indexing _p_ and minimizers appearing once
|
void *h; // hash table indexing _p_ and minimizers appearing once
|
||||||
} mm_idx_bucket_t;
|
} mm_idx_bucket_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t st, en, max; // max is not used for now
|
||||||
|
int32_t score:30, strand:2;
|
||||||
|
} mm_idx_intv1_t;
|
||||||
|
|
||||||
|
typedef struct mm_idx_intv_s {
|
||||||
|
int32_t n, m;
|
||||||
|
mm_idx_intv1_t *a;
|
||||||
|
} mm_idx_intv_t;
|
||||||
|
|
||||||
mm_idx_t *mm_idx_init(int w, int k, int b, int flag)
|
mm_idx_t *mm_idx_init(int w, int k, int b, int flag)
|
||||||
{
|
{
|
||||||
mm_idx_t *mi;
|
mm_idx_t *mi;
|
||||||
@@ -55,12 +65,17 @@ void mm_idx_destroy(mm_idx_t *mi)
|
|||||||
kh_destroy(idx, (idxhash_t*)mi->B[i].h);
|
kh_destroy(idx, (idxhash_t*)mi->B[i].h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mi->I) {
|
||||||
|
for (i = 0; i < mi->n_seq; ++i)
|
||||||
|
free(mi->I[i].a);
|
||||||
|
free(mi->I);
|
||||||
|
}
|
||||||
if (!mi->km) {
|
if (!mi->km) {
|
||||||
for (i = 0; i < mi->n_seq; ++i)
|
for (i = 0; i < mi->n_seq; ++i)
|
||||||
free(mi->seq[i].name);
|
free(mi->seq[i].name);
|
||||||
free(mi->seq);
|
free(mi->seq);
|
||||||
} else km_destroy(mi->km);
|
} else km_destroy(mi->km);
|
||||||
free(mi->R); free(mi->B); free(mi->S); free(mi);
|
free(mi->B); free(mi->S); free(mi);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint64_t *mm_idx_get(const mm_idx_t *mi, uint64_t minier, int *n)
|
const uint64_t *mm_idx_get(const mm_idx_t *mi, uint64_t minier, int *n)
|
||||||
@@ -102,8 +117,8 @@ void mm_idx_stat(const mm_idx_t *mi)
|
|||||||
if (kh_key(h, k)&1) ++n1;
|
if (kh_key(h, k)&1) ++n1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(stderr, "[M::%s::%.3f*%.2f] distinct minimizers: %d (%.2f%% are singletons); average occurrences: %.3lf; average spacing: %.3lf\n",
|
fprintf(stderr, "[M::%s::%.3f*%.2f] distinct minimizers: %d (%.2f%% are singletons); average occurrences: %.3lf; average spacing: %.3lf; total length: %ld\n",
|
||||||
__func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), n, 100.0*n1/n, (double)sum / n, (double)len / sum);
|
__func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), n, 100.0*n1/n, (double)sum / n, (double)len / sum, (long)len);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_idx_index_name(mm_idx_t *mi)
|
int mm_idx_index_name(mm_idx_t *mi)
|
||||||
@@ -134,7 +149,7 @@ int mm_idx_name2id(const mm_idx_t *mi, const char *name)
|
|||||||
return k == kh_end(h)? -1 : kh_val(h, k);
|
return k == kh_end(h)? -1 : kh_val(h, k);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_idx_getseq2(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq, int8_t *b)
|
int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq)
|
||||||
{
|
{
|
||||||
uint64_t i, st1, en1;
|
uint64_t i, st1, en1;
|
||||||
if (rid >= mi->n_seq || st >= mi->seq[rid].len) return -1;
|
if (rid >= mi->n_seq || st >= mi->seq[rid].len) return -1;
|
||||||
@@ -143,25 +158,30 @@ int mm_idx_getseq2(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, u
|
|||||||
en1 = mi->seq[rid].offset + en;
|
en1 = mi->seq[rid].offset + en;
|
||||||
for (i = st1; i < en1; ++i)
|
for (i = st1; i < en1; ++i)
|
||||||
seq[i - st1] = mm_seq4_get(mi->S, i);
|
seq[i - st1] = mm_seq4_get(mi->S, i);
|
||||||
if (b) memset(b, 0, en - st);
|
return en - st;
|
||||||
if (b && mi->R) {
|
}
|
||||||
uint32_t i, z;
|
|
||||||
memset(b, 0, en - st);
|
int mm_idx_getseq_rev(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq)
|
||||||
z = mm_idx_bed_query(mi, (uint64_t)rid << 32 | st);
|
{
|
||||||
for (i = z < 0? 0 : z; i < mi->n_R; ++i) {
|
uint64_t i, st1, en1;
|
||||||
uint32_t j, rr, rs, re;
|
const mm_idx_seq_t *s;
|
||||||
rr = mi->R[i].x >> 32, rs = (uint32_t)mi->R[i].x, re = mi->R[i].end;
|
if (rid >= mi->n_seq || st >= mi->seq[rid].len) return -1;
|
||||||
if (rr > rid || rs >= en) break;
|
s = &mi->seq[rid];
|
||||||
if (rr < rid) continue;
|
if (en > s->len) en = s->len;
|
||||||
re = re < en? re : en;
|
st1 = s->offset + (s->len - en);
|
||||||
for (j = st > rs? st : rs; j < re; ++j)
|
en1 = s->offset + (s->len - st);
|
||||||
b[j - st] = mi->R[i].score;
|
for (i = st1; i < en1; ++i) {
|
||||||
}
|
uint8_t c = mm_seq4_get(mi->S, i);
|
||||||
|
seq[en1 - i - 1] = c < 4? 3 - c : c;
|
||||||
}
|
}
|
||||||
return en - st;
|
return en - st;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq) { return mm_idx_getseq2(mi, rid, st, en, seq, 0); }
|
int mm_idx_getseq2(const mm_idx_t *mi, int is_rev, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq)
|
||||||
|
{
|
||||||
|
if (is_rev) return mm_idx_getseq_rev(mi, rid, st, en, seq);
|
||||||
|
else return mm_idx_getseq(mi, rid, st, en, seq);
|
||||||
|
}
|
||||||
|
|
||||||
int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f)
|
int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f)
|
||||||
{
|
{
|
||||||
@@ -318,6 +338,7 @@ static void *worker_pipeline(void *shared, int step, void *in)
|
|||||||
} else seq->name = 0;
|
} else seq->name = 0;
|
||||||
seq->len = s->seq[i].l_seq;
|
seq->len = s->seq[i].l_seq;
|
||||||
seq->offset = p->sum_len;
|
seq->offset = p->sum_len;
|
||||||
|
seq->is_alt = 0;
|
||||||
// copy the sequence
|
// copy the sequence
|
||||||
if (!(p->mi->flag & MM_I_NO_SEQ)) {
|
if (!(p->mi->flag & MM_I_NO_SEQ)) {
|
||||||
for (j = 0; j < seq->len; ++j) { // TODO: this is not the fastest way, but let's first see if speed matters here
|
for (j = 0; j < seq->len; ++j) { // TODO: this is not the fastest way, but let's first see if speed matters here
|
||||||
@@ -416,6 +437,7 @@ mm_idx_t *mm_idx_str(int w, int k, int is_hpc, int bucket_bits, int n, const cha
|
|||||||
}
|
}
|
||||||
p->offset = sum_len;
|
p->offset = sum_len;
|
||||||
p->len = strlen(s);
|
p->len = strlen(s);
|
||||||
|
p->is_alt = 0;
|
||||||
for (j = 0; j < p->len; ++j) {
|
for (j = 0; j < p->len; ++j) {
|
||||||
int c = seq_nt4_table[(uint8_t)s[j]];
|
int c = seq_nt4_table[(uint8_t)s[j]];
|
||||||
uint64_t o = sum_len + j;
|
uint64_t o = sum_len + j;
|
||||||
@@ -502,6 +524,7 @@ mm_idx_t *mm_idx_load(FILE *fp)
|
|||||||
}
|
}
|
||||||
fread(&s->len, 4, 1, fp);
|
fread(&s->len, 4, 1, fp);
|
||||||
s->offset = sum_len;
|
s->offset = sum_len;
|
||||||
|
s->is_alt = 0;
|
||||||
sum_len += s->len;
|
sum_len += s->len;
|
||||||
}
|
}
|
||||||
for (i = 0; i < 1<<mi->b; ++i) {
|
for (i = 0; i < 1<<mi->b; ++i) {
|
||||||
@@ -609,82 +632,144 @@ int mm_idx_reader_eof(const mm_idx_reader_t *r) // TODO: in extremely rare cases
|
|||||||
#include "kseq.h"
|
#include "kseq.h"
|
||||||
KSTREAM_DECLARE(gzFile, gzread)
|
KSTREAM_DECLARE(gzFile, gzread)
|
||||||
|
|
||||||
#define sort_key_bed(a) ((a).x)
|
int mm_idx_alt_read(mm_idx_t *mi, const char *fn)
|
||||||
KRADIX_SORT_INIT(bed, mm_idx_bed_t, sort_key_bed, 8)
|
{
|
||||||
|
int n_alt = 0;
|
||||||
|
gzFile fp;
|
||||||
|
kstream_t *ks;
|
||||||
|
kstring_t str = {0,0,0};
|
||||||
|
fp = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
|
||||||
|
if (fp == 0) return -1;
|
||||||
|
ks = ks_init(fp);
|
||||||
|
if (mi->h == 0) mm_idx_index_name(mi);
|
||||||
|
while (ks_getuntil(ks, KS_SEP_LINE, &str, 0) >= 0) {
|
||||||
|
char *p;
|
||||||
|
int id;
|
||||||
|
for (p = str.s; *p && !isspace(*p); ++p) { }
|
||||||
|
*p = 0;
|
||||||
|
id = mm_idx_name2id(mi, str.s);
|
||||||
|
if (id >= 0) mi->seq[id].is_alt = 1, ++n_alt;
|
||||||
|
}
|
||||||
|
mi->n_alt = n_alt;
|
||||||
|
if (mm_verbose >= 3)
|
||||||
|
fprintf(stderr, "[M::%s] found %d ALT contigs\n", __func__, n_alt);
|
||||||
|
return n_alt;
|
||||||
|
}
|
||||||
|
|
||||||
mm_idx_bed_t *mm_idx_bed_read_list(const mm_idx_t *mi, const char *fn, uint32_t *n_)
|
#define sort_key_bed(a) ((a).st)
|
||||||
|
KRADIX_SORT_INIT(bed, mm_idx_intv1_t, sort_key_bed, 4)
|
||||||
|
|
||||||
|
mm_idx_intv_t *mm_idx_read_bed(const mm_idx_t *mi, const char *fn, int read_junc)
|
||||||
{
|
{
|
||||||
gzFile fp;
|
gzFile fp;
|
||||||
kstream_t *ks;
|
kstream_t *ks;
|
||||||
kstring_t str = {0,0,0};
|
kstring_t str = {0,0,0};
|
||||||
uint32_t n = 0, m = 0;
|
mm_idx_intv_t *I;
|
||||||
mm_idx_bed_t *r = 0;
|
|
||||||
|
|
||||||
fp = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
|
fp = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
|
||||||
if (fp == 0) return 0;
|
if (fp == 0) return 0;
|
||||||
|
I = (mm_idx_intv_t*)calloc(mi->n_seq, sizeof(*I));
|
||||||
ks = ks_init(fp);
|
ks = ks_init(fp);
|
||||||
while (ks_getuntil(ks, KS_SEP_LINE, &str, 0) >= 0) {
|
while (ks_getuntil(ks, KS_SEP_LINE, &str, 0) >= 0) {
|
||||||
mm_idx_bed_t t;
|
mm_idx_intv_t *r;
|
||||||
char *p, *q;
|
mm_idx_intv1_t t = {-1,-1,-1,-1,0};
|
||||||
int i, id = -1, st = -1, en = -1, sc = -1;
|
char *p, *q, *bl, *bs;
|
||||||
|
int32_t i, id = -1, n_blk = 0;
|
||||||
for (p = q = str.s, i = 0;; ++p) {
|
for (p = q = str.s, i = 0;; ++p) {
|
||||||
if (*p == 0 || isspace(*p)) {
|
if (*p == 0 || *p == '\t') {
|
||||||
int32_t c = *p;
|
int32_t c = *p;
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if (i == 0) { // chr
|
if (i == 0) { // chr
|
||||||
id = mm_idx_name2id(mi, q);
|
id = mm_idx_name2id(mi, q);
|
||||||
if (id < 0) break; // unknown name; TODO: throw a warning
|
if (id < 0) break; // unknown name; TODO: throw a warning
|
||||||
} else if (i == 1) { // start
|
} else if (i == 1) { // start
|
||||||
st = atoi(q);
|
t.st = atol(q); // TODO: watch out integer overflow!
|
||||||
if (st < 0) break;
|
if (t.st < 0) break;
|
||||||
} else if (i == 2) { // end
|
} else if (i == 2) { // end
|
||||||
en = atoi(q);
|
t.en = atol(q);
|
||||||
if (en < 0) break;
|
if (t.en < 0) break;
|
||||||
} else if (i == 3) { // name; do nothing
|
|
||||||
} else if (i == 4) { // BED score
|
} else if (i == 4) { // BED score
|
||||||
sc = atoi(q);
|
t.score = atol(q);
|
||||||
assert(sc >= 0 && sc <= 127);
|
} else if (i == 5) { // strand
|
||||||
} else break;
|
t.strand = *q == '+'? 1 : *q == '-'? -1 : 0;
|
||||||
|
} else if (i == 9) {
|
||||||
|
if (!isdigit(*q)) break;
|
||||||
|
n_blk = atol(q);
|
||||||
|
} else if (i == 10) {
|
||||||
|
bl = q;
|
||||||
|
} else if (i == 11) {
|
||||||
|
bs = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (c == 0) break;
|
if (c == 0) break;
|
||||||
++i, q = p + 1;
|
++i, q = p + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (en < 0) en = st + 1;
|
if (id < 0 || t.st < 0 || t.st >= t.en) continue;
|
||||||
if (st < 0 || st >= en) continue;
|
r = &I[id];
|
||||||
if (m == n) EXPAND(r, m);
|
if (i >= 11 && read_junc) { // BED12
|
||||||
t.x = (uint64_t)id << 32 | st, t.end = en, t.score = sc >= 0? sc : 0, t.idx = -1;
|
int32_t st, sz, en;
|
||||||
r[n++] = t;
|
st = strtol(bs, &bs, 10); ++bs;
|
||||||
|
sz = strtol(bl, &bl, 10); ++bl;
|
||||||
|
en = t.st + st + sz;
|
||||||
|
for (i = 1; i < n_blk; ++i) {
|
||||||
|
mm_idx_intv1_t s = t;
|
||||||
|
if (r->n == r->m) {
|
||||||
|
r->m = r->m? r->m + (r->m>>1) : 16;
|
||||||
|
r->a = (mm_idx_intv1_t*)realloc(r->a, sizeof(*r->a) * r->m);
|
||||||
|
}
|
||||||
|
st = strtol(bs, &bs, 10); ++bs;
|
||||||
|
sz = strtol(bl, &bl, 10); ++bl;
|
||||||
|
s.st = en, s.en = t.st + st;
|
||||||
|
en = t.st + st + sz;
|
||||||
|
if (s.en > s.st) r->a[r->n++] = s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (r->n == r->m) {
|
||||||
|
r->m = r->m? r->m + (r->m>>1) : 16;
|
||||||
|
r->a = (mm_idx_intv1_t*)realloc(r->a, sizeof(*r->a) * r->m);
|
||||||
|
}
|
||||||
|
r->a[r->n++] = t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
free(str.s);
|
||||||
ks_destroy(ks);
|
ks_destroy(ks);
|
||||||
gzclose(fp);
|
gzclose(fp);
|
||||||
*n_ = n;
|
return I;
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_idx_bed_attach(mm_idx_t *mi, uint32_t n, mm_idx_bed_t *r) // TODO: check errors
|
int mm_idx_bed_read(mm_idx_t *mi, const char *fn, int read_junc)
|
||||||
{
|
{
|
||||||
radix_sort_bed(r, r + n);
|
int32_t i;
|
||||||
mi->R = r, mi->n_R = n;
|
if (mi->h == 0) mm_idx_index_name(mi);
|
||||||
|
mi->I = mm_idx_read_bed(mi, fn, read_junc);
|
||||||
|
if (mi->I == 0) return -1;
|
||||||
|
for (i = 0; i < mi->n_seq; ++i) // TODO: eliminate redundant intervals
|
||||||
|
radix_sort_bed(mi->I[i].a, mi->I[i].a + mi->I[i].n);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_idx_bed_read(mm_idx_t *mi, const char *fn)
|
int mm_idx_bed_junc(const mm_idx_t *mi, int32_t ctg, int32_t st, int32_t en, uint8_t *s)
|
||||||
{
|
{
|
||||||
mm_idx_bed_t *r;
|
int32_t i, left, right;
|
||||||
uint32_t n;
|
mm_idx_intv_t *r;
|
||||||
if (mi->h == 0) mm_idx_index_name(mi);
|
memset(s, 0, en - st);
|
||||||
r = mm_idx_bed_read_list(mi, fn, &n);
|
if (mi->I == 0 || ctg < 0 || ctg >= mi->n_seq) return -1;
|
||||||
return mm_idx_bed_attach(mi, n, r);
|
r = &mi->I[ctg];
|
||||||
}
|
left = 0, right = r->n;
|
||||||
|
while (right > left) {
|
||||||
int mm_idx_bed_query(const mm_idx_t *mi, uint64_t x)
|
|
||||||
{
|
|
||||||
int32_t left = -1, right = mi->n_R;
|
|
||||||
while (right - left > 1) {
|
|
||||||
int32_t mid = left + ((right - left) >> 1);
|
int32_t mid = left + ((right - left) >> 1);
|
||||||
if (mi->R[mid].x > x) right = mid;
|
if (r->a[mid].st >= st) right = mid;
|
||||||
else if (mi->R[mid].x < x) left = mid;
|
else left = mid + 1;
|
||||||
else return mid;
|
}
|
||||||
|
for (i = left; i < r->n; ++i) {
|
||||||
|
if (st <= r->a[i].st && en >= r->a[i].en && r->a[i].strand != 0) {
|
||||||
|
if (r->a[i].strand > 0) {
|
||||||
|
s[r->a[i].st - st] |= 1, s[r->a[i].en - 1 - st] |= 2;
|
||||||
|
} else {
|
||||||
|
s[r->a[i].st - st] |= 8, s[r->a[i].en - 1 - st] |= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,14 @@
|
|||||||
* | | | |
|
* | | | |
|
||||||
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
|
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MIN_CORE_SIZE 0x80000
|
|
||||||
|
|
||||||
typedef struct header_t {
|
typedef struct header_t {
|
||||||
size_t size;
|
size_t size;
|
||||||
struct header_t *ptr;
|
struct header_t *ptr;
|
||||||
} header_t;
|
} header_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
void *par;
|
||||||
|
size_t min_core_size;
|
||||||
header_t base, *loop_head, *core_head; /* base is a zero-sized block always kept in the loop */
|
header_t base, *loop_head, *core_head; /* base is a zero-sized block always kept in the loop */
|
||||||
} kmem_t;
|
} kmem_t;
|
||||||
|
|
||||||
@@ -36,31 +35,39 @@ static void panic(const char *s)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void *km_init(void)
|
void *km_init2(void *km_par, size_t min_core_size)
|
||||||
{
|
{
|
||||||
return calloc(1, sizeof(kmem_t));
|
kmem_t *km;
|
||||||
|
km = (kmem_t*)kcalloc(km_par, 1, sizeof(kmem_t));
|
||||||
|
km->par = km_par;
|
||||||
|
km->min_core_size = min_core_size > 0? min_core_size : 0x80000;
|
||||||
|
return (void*)km;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *km_init(void) { return km_init2(0, 0); }
|
||||||
|
|
||||||
void km_destroy(void *_km)
|
void km_destroy(void *_km)
|
||||||
{
|
{
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
|
void *km_par;
|
||||||
header_t *p, *q;
|
header_t *p, *q;
|
||||||
if (km == NULL) return;
|
if (km == NULL) return;
|
||||||
|
km_par = km->par;
|
||||||
for (p = km->core_head; p != NULL;) {
|
for (p = km->core_head; p != NULL;) {
|
||||||
q = p->ptr;
|
q = p->ptr;
|
||||||
free(p);
|
kfree(km_par, p);
|
||||||
p = q;
|
p = q;
|
||||||
}
|
}
|
||||||
free(km);
|
kfree(km_par, km);
|
||||||
}
|
}
|
||||||
|
|
||||||
static header_t *morecore(kmem_t *km, size_t nu)
|
static header_t *morecore(kmem_t *km, size_t nu)
|
||||||
{
|
{
|
||||||
header_t *q;
|
header_t *q;
|
||||||
size_t bytes, *p;
|
size_t bytes, *p;
|
||||||
nu = (nu + 1 + (MIN_CORE_SIZE - 1)) / MIN_CORE_SIZE * MIN_CORE_SIZE; /* the first +1 for core header */
|
nu = (nu + 1 + (km->min_core_size - 1)) / km->min_core_size * km->min_core_size; /* the first +1 for core header */
|
||||||
bytes = nu * sizeof(header_t);
|
bytes = nu * sizeof(header_t);
|
||||||
q = (header_t*)malloc(bytes);
|
q = (header_t*)kmalloc(km->par, bytes);
|
||||||
if (!q) panic("[morecore] insufficient memory");
|
if (!q) panic("[morecore] insufficient memory");
|
||||||
q->ptr = km->core_head, q->size = nu, km->core_head = q;
|
q->ptr = km->core_head, q->size = nu, km->core_head = q;
|
||||||
p = (size_t*)(q + 1);
|
p = (size_t*)(q + 1);
|
||||||
@@ -125,7 +132,7 @@ void *kmalloc(void *_km, size_t n_bytes)
|
|||||||
|
|
||||||
if (n_bytes == 0) return 0;
|
if (n_bytes == 0) return 0;
|
||||||
if (km == NULL) return malloc(n_bytes);
|
if (km == NULL) return malloc(n_bytes);
|
||||||
n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t) + 1;
|
n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t); /* header+n_bytes requires at least this number of units */
|
||||||
|
|
||||||
if (!(q = km->loop_head)) /* the first time when kmalloc() is called, intialize it */
|
if (!(q = km->loop_head)) /* the first time when kmalloc() is called, intialize it */
|
||||||
q = km->loop_head = km->base.ptr = &km->base;
|
q = km->loop_head = km->base.ptr = &km->base;
|
||||||
@@ -160,18 +167,18 @@ void *kcalloc(void *_km, size_t count, size_t size)
|
|||||||
void *krealloc(void *_km, void *ap, size_t n_bytes) // TODO: this can be made more efficient in principle
|
void *krealloc(void *_km, void *ap, size_t n_bytes) // TODO: this can be made more efficient in principle
|
||||||
{
|
{
|
||||||
kmem_t *km = (kmem_t*)_km;
|
kmem_t *km = (kmem_t*)_km;
|
||||||
size_t n_units, *p, *q;
|
size_t cap, *p, *q;
|
||||||
|
|
||||||
if (n_bytes == 0) {
|
if (n_bytes == 0) {
|
||||||
kfree(km, ap); return 0;
|
kfree(km, ap); return 0;
|
||||||
}
|
}
|
||||||
if (km == NULL) return realloc(ap, n_bytes);
|
if (km == NULL) return realloc(ap, n_bytes);
|
||||||
if (ap == NULL) return kmalloc(km, n_bytes);
|
if (ap == NULL) return kmalloc(km, n_bytes);
|
||||||
n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t);
|
|
||||||
p = (size_t*)ap - 1;
|
p = (size_t*)ap - 1;
|
||||||
if (*p >= n_units) return ap; /* TODO: this prevents shrinking */
|
cap = (*p) * sizeof(header_t) - sizeof(size_t);
|
||||||
|
if (cap >= n_bytes) return ap; /* TODO: this prevents shrinking */
|
||||||
q = (size_t*)kmalloc(km, n_bytes);
|
q = (size_t*)kmalloc(km, n_bytes);
|
||||||
memcpy(q, ap, (*p - 1) * sizeof(header_t));
|
memcpy(q, ap, cap);
|
||||||
kfree(km, ap);
|
kfree(km, ap);
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ void *kcalloc(void *km, size_t count, size_t size);
|
|||||||
void kfree(void *km, void *ptr);
|
void kfree(void *km, void *ptr);
|
||||||
|
|
||||||
void *km_init(void);
|
void *km_init(void);
|
||||||
|
void *km_init2(void *km_par, size_t min_core_size);
|
||||||
void km_destroy(void *km);
|
void km_destroy(void *km);
|
||||||
void km_stat(const void *_km, km_stat_t *s);
|
void km_stat(const void *_km, km_stat_t *s);
|
||||||
|
|
||||||
@@ -24,4 +25,52 @@ void km_stat(const void *_km, km_stat_t *s);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define KMALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kmalloc((km), (len) * sizeof(*(ptr))))
|
||||||
|
#define KCALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kcalloc((km), (len), sizeof(*(ptr))))
|
||||||
|
#define KREALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))krealloc((km), (ptr), (len) * sizeof(*(ptr))))
|
||||||
|
|
||||||
|
#define KEXPAND(km, a, m) do { \
|
||||||
|
(m) = (m) >= 4? (m) + ((m)>>1) : 16; \
|
||||||
|
KREALLOC((km), (a), (m)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#ifndef klib_unused
|
||||||
|
#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
|
||||||
|
#define klib_unused __attribute__ ((__unused__))
|
||||||
|
#else
|
||||||
|
#define klib_unused
|
||||||
|
#endif
|
||||||
|
#endif /* klib_unused */
|
||||||
|
|
||||||
|
#define KALLOC_POOL_INIT2(SCOPE, name, kmptype_t) \
|
||||||
|
typedef struct { \
|
||||||
|
size_t cnt, n, max; \
|
||||||
|
kmptype_t **buf; \
|
||||||
|
void *km; \
|
||||||
|
} kmp_##name##_t; \
|
||||||
|
SCOPE kmp_##name##_t *kmp_init_##name(void *km) { \
|
||||||
|
kmp_##name##_t *mp; \
|
||||||
|
KCALLOC(km, mp, 1); \
|
||||||
|
mp->km = km; \
|
||||||
|
return mp; \
|
||||||
|
} \
|
||||||
|
SCOPE void kmp_destroy_##name(kmp_##name##_t *mp) { \
|
||||||
|
size_t k; \
|
||||||
|
for (k = 0; k < mp->n; ++k) kfree(mp->km, mp->buf[k]); \
|
||||||
|
kfree(mp->km, mp->buf); kfree(mp->km, mp); \
|
||||||
|
} \
|
||||||
|
SCOPE kmptype_t *kmp_alloc_##name(kmp_##name##_t *mp) { \
|
||||||
|
++mp->cnt; \
|
||||||
|
if (mp->n == 0) return (kmptype_t*)kcalloc(mp->km, 1, sizeof(kmptype_t)); \
|
||||||
|
return mp->buf[--mp->n]; \
|
||||||
|
} \
|
||||||
|
SCOPE void kmp_free_##name(kmp_##name##_t *mp, kmptype_t *p) { \
|
||||||
|
--mp->cnt; \
|
||||||
|
if (mp->n == mp->max) KEXPAND(mp->km, mp->buf, mp->max); \
|
||||||
|
mp->buf[mp->n++] = p; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define KALLOC_POOL_INIT(name, kmptype_t) \
|
||||||
|
KALLOC_POOL_INIT2(static inline klib_unused, name, kmptype_t)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -73,13 +73,17 @@ static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *
|
|||||||
}
|
}
|
||||||
s->opt = 0, opt = '?', s->pos = -1;
|
s->opt = 0, opt = '?', s->pos = -1;
|
||||||
if (longopts) { /* parse long options */
|
if (longopts) { /* parse long options */
|
||||||
int k, n_matches = 0;
|
int k, n_exact = 0, n_partial = 0;
|
||||||
const ko_longopt_t *o = 0;
|
const ko_longopt_t *o = 0, *o_exact = 0, *o_partial = 0;
|
||||||
for (j = 2; argv[s->i][j] != '\0' && argv[s->i][j] != '='; ++j) {} /* find the end of the option name */
|
for (j = 2; argv[s->i][j] != '\0' && argv[s->i][j] != '='; ++j) {} /* find the end of the option name */
|
||||||
for (k = 0; longopts[k].name != 0; ++k)
|
for (k = 0; longopts[k].name != 0; ++k)
|
||||||
if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0)
|
if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0) {
|
||||||
++n_matches, o = &longopts[k];
|
if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k];
|
||||||
if (n_matches == 1) {
|
else ++n_partial, o_partial = &longopts[k];
|
||||||
|
}
|
||||||
|
if (n_exact > 1 || (n_exact == 0 && n_partial > 1)) return '?';
|
||||||
|
o = n_exact == 1? o_exact : n_partial == 1? o_partial : 0;
|
||||||
|
if (o) {
|
||||||
s->opt = opt = o->val, s->longidx = o - longopts;
|
s->opt = opt = o->val, s->longidx = o - longopts;
|
||||||
if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1];
|
if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1];
|
||||||
if (o->has_arg == 1 && argv[s->i][j] == '\0') {
|
if (o->has_arg == 1 && argv[s->i][j] == '\0') {
|
||||||
@@ -92,7 +96,7 @@ static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *
|
|||||||
char *p;
|
char *p;
|
||||||
if (s->pos == 0) s->pos = 1;
|
if (s->pos == 0) s->pos = 1;
|
||||||
opt = s->opt = argv[s->i][s->pos++];
|
opt = s->opt = argv[s->i][s->pos++];
|
||||||
p = strchr(ostr, opt);
|
p = strchr((char*)ostr, opt);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
opt = '?'; /* unknown option */
|
opt = '?'; /* unknown option */
|
||||||
} else if (p[1] == ':') {
|
} else if (p[1] == ':') {
|
||||||
|
|||||||
@@ -0,0 +1,474 @@
|
|||||||
|
/* The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 by Attractive Chaos <attractor@live.co.uk>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* An example:
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "krmq.h"
|
||||||
|
|
||||||
|
struct my_node {
|
||||||
|
char key;
|
||||||
|
KRMQ_HEAD(struct my_node) head;
|
||||||
|
};
|
||||||
|
#define my_cmp(p, q) (((q)->key < (p)->key) - ((p)->key < (q)->key))
|
||||||
|
KRMQ_INIT(my, struct my_node, head, my_cmp)
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
const char *str = "MNOLKQOPHIA"; // from wiki, except a duplicate
|
||||||
|
struct my_node *root = 0;
|
||||||
|
int i, l = strlen(str);
|
||||||
|
for (i = 0; i < l; ++i) { // insert in the input order
|
||||||
|
struct my_node *q, *p = malloc(sizeof(*p));
|
||||||
|
p->key = str[i];
|
||||||
|
q = krmq_insert(my, &root, p, 0);
|
||||||
|
if (p != q) free(p); // if already present, free
|
||||||
|
}
|
||||||
|
krmq_itr_t(my) itr;
|
||||||
|
krmq_itr_first(my, root, &itr); // place at first
|
||||||
|
do { // traverse
|
||||||
|
const struct my_node *p = krmq_at(&itr);
|
||||||
|
putchar(p->key);
|
||||||
|
free((void*)p); // free node
|
||||||
|
} while (krmq_itr_next(my, &itr));
|
||||||
|
putchar('\n');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KRMQ_H
|
||||||
|
#define KRMQ_H
|
||||||
|
|
||||||
|
#ifdef __STRICT_ANSI__
|
||||||
|
#define inline __inline__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define KRMQ_MAX_DEPTH 64
|
||||||
|
|
||||||
|
#define krmq_size(head, p) ((p)? (p)->head.size : 0)
|
||||||
|
#define krmq_size_child(head, q, i) ((q)->head.p[(i)]? (q)->head.p[(i)]->head.size : 0)
|
||||||
|
|
||||||
|
#define KRMQ_HEAD(__type) \
|
||||||
|
struct { \
|
||||||
|
__type *p[2], *s; \
|
||||||
|
signed char balance; /* balance factor */ \
|
||||||
|
unsigned size; /* #elements in subtree */ \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __KRMQ_FIND(suf, __scope, __type, __head, __cmp) \
|
||||||
|
__scope __type *krmq_find_##suf(const __type *root, const __type *x, unsigned *cnt_) { \
|
||||||
|
const __type *p = root; \
|
||||||
|
unsigned cnt = 0; \
|
||||||
|
while (p != 0) { \
|
||||||
|
int cmp; \
|
||||||
|
cmp = __cmp(x, p); \
|
||||||
|
if (cmp >= 0) cnt += krmq_size_child(__head, p, 0) + 1; \
|
||||||
|
if (cmp < 0) p = p->__head.p[0]; \
|
||||||
|
else if (cmp > 0) p = p->__head.p[1]; \
|
||||||
|
else break; \
|
||||||
|
} \
|
||||||
|
if (cnt_) *cnt_ = cnt; \
|
||||||
|
return (__type*)p; \
|
||||||
|
} \
|
||||||
|
__scope __type *krmq_interval_##suf(const __type *root, const __type *x, __type **lower, __type **upper) { \
|
||||||
|
const __type *p = root, *l = 0, *u = 0; \
|
||||||
|
while (p != 0) { \
|
||||||
|
int cmp; \
|
||||||
|
cmp = __cmp(x, p); \
|
||||||
|
if (cmp < 0) u = p, p = p->__head.p[0]; \
|
||||||
|
else if (cmp > 0) l = p, p = p->__head.p[1]; \
|
||||||
|
else { l = u = p; break; } \
|
||||||
|
} \
|
||||||
|
if (lower) *lower = (__type*)l; \
|
||||||
|
if (upper) *upper = (__type*)u; \
|
||||||
|
return (__type*)p; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __KRMQ_RMQ(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__scope __type *krmq_rmq_##suf(const __type *root, const __type *lo, const __type *up) { /* CLOSED interval */ \
|
||||||
|
const __type *p = root, *path[2][KRMQ_MAX_DEPTH], *min; \
|
||||||
|
int plen[2] = {0, 0}, pcmp[2][KRMQ_MAX_DEPTH], i, cmp, lca; \
|
||||||
|
if (root == 0) return 0; \
|
||||||
|
while (p) { \
|
||||||
|
cmp = __cmp(lo, p); \
|
||||||
|
path[0][plen[0]] = p, pcmp[0][plen[0]++] = cmp; \
|
||||||
|
if (cmp < 0) p = p->__head.p[0]; \
|
||||||
|
else if (cmp > 0) p = p->__head.p[1]; \
|
||||||
|
else break; \
|
||||||
|
} \
|
||||||
|
p = root; \
|
||||||
|
while (p) { \
|
||||||
|
cmp = __cmp(up, p); \
|
||||||
|
path[1][plen[1]] = p, pcmp[1][plen[1]++] = cmp; \
|
||||||
|
if (cmp < 0) p = p->__head.p[0]; \
|
||||||
|
else if (cmp > 0) p = p->__head.p[1]; \
|
||||||
|
else break; \
|
||||||
|
} \
|
||||||
|
for (i = 0; i < plen[0] && i < plen[1]; ++i) /* find the LCA */ \
|
||||||
|
if (path[0][i] == path[1][i] && pcmp[0][i] <= 0 && pcmp[1][i] >= 0) \
|
||||||
|
break; \
|
||||||
|
if (i == plen[0] || i == plen[1]) return 0; /* no elements in the closed interval */ \
|
||||||
|
lca = i, min = path[0][lca]; \
|
||||||
|
for (i = lca + 1; i < plen[0]; ++i) { \
|
||||||
|
if (pcmp[0][i] <= 0) { \
|
||||||
|
if (__lt2(path[0][i], min)) min = path[0][i]; \
|
||||||
|
if (path[0][i]->__head.p[1] && __lt2(path[0][i]->__head.p[1]->__head.s, min)) \
|
||||||
|
min = path[0][i]->__head.p[1]->__head.s; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
for (i = lca + 1; i < plen[1]; ++i) { \
|
||||||
|
if (pcmp[1][i] >= 0) { \
|
||||||
|
if (__lt2(path[1][i], min)) min = path[1][i]; \
|
||||||
|
if (path[1][i]->__head.p[0] && __lt2(path[1][i]->__head.p[0]->__head.s, min)) \
|
||||||
|
min = path[1][i]->__head.p[0]->__head.s; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
return (__type*)min; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __KRMQ_ROTATE(suf, __type, __head, __lt2) \
|
||||||
|
/* */ \
|
||||||
|
static inline void krmq_update_min_##suf(__type *p, const __type *q, const __type *r) { \
|
||||||
|
p->__head.s = !q || __lt2(p, q->__head.s)? p : q->__head.s; \
|
||||||
|
p->__head.s = !r || __lt2(p->__head.s, r->__head.s)? p->__head.s : r->__head.s; \
|
||||||
|
} \
|
||||||
|
/* one rotation: (a,(b,c)q)p => ((a,b)p,c)q */ \
|
||||||
|
static inline __type *krmq_rotate1_##suf(__type *p, int dir) { /* dir=0 to left; dir=1 to right */ \
|
||||||
|
int opp = 1 - dir; /* opposite direction */ \
|
||||||
|
__type *q = p->__head.p[opp], *s = p->__head.s; \
|
||||||
|
unsigned size_p = p->__head.size; \
|
||||||
|
p->__head.size -= q->__head.size - krmq_size_child(__head, q, dir); \
|
||||||
|
q->__head.size = size_p; \
|
||||||
|
krmq_update_min_##suf(p, p->__head.p[dir], q->__head.p[dir]); \
|
||||||
|
q->__head.s = s; \
|
||||||
|
p->__head.p[opp] = q->__head.p[dir]; \
|
||||||
|
q->__head.p[dir] = p; \
|
||||||
|
return q; \
|
||||||
|
} \
|
||||||
|
/* two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r */ \
|
||||||
|
static inline __type *krmq_rotate2_##suf(__type *p, int dir) { \
|
||||||
|
int b1, opp = 1 - dir; \
|
||||||
|
__type *q = p->__head.p[opp], *r = q->__head.p[dir], *s = p->__head.s; \
|
||||||
|
unsigned size_x_dir = krmq_size_child(__head, r, dir); \
|
||||||
|
r->__head.size = p->__head.size; \
|
||||||
|
p->__head.size -= q->__head.size - size_x_dir; \
|
||||||
|
q->__head.size -= size_x_dir + 1; \
|
||||||
|
krmq_update_min_##suf(p, p->__head.p[dir], r->__head.p[dir]); \
|
||||||
|
krmq_update_min_##suf(q, q->__head.p[opp], r->__head.p[opp]); \
|
||||||
|
r->__head.s = s; \
|
||||||
|
p->__head.p[opp] = r->__head.p[dir]; \
|
||||||
|
r->__head.p[dir] = p; \
|
||||||
|
q->__head.p[dir] = r->__head.p[opp]; \
|
||||||
|
r->__head.p[opp] = q; \
|
||||||
|
b1 = dir == 0? +1 : -1; \
|
||||||
|
if (r->__head.balance == b1) q->__head.balance = 0, p->__head.balance = -b1; \
|
||||||
|
else if (r->__head.balance == 0) q->__head.balance = p->__head.balance = 0; \
|
||||||
|
else q->__head.balance = b1, p->__head.balance = 0; \
|
||||||
|
r->__head.balance = 0; \
|
||||||
|
return r; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __KRMQ_INSERT(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__scope __type *krmq_insert_##suf(__type **root_, __type *x, unsigned *cnt_) { \
|
||||||
|
unsigned char stack[KRMQ_MAX_DEPTH]; \
|
||||||
|
__type *path[KRMQ_MAX_DEPTH]; \
|
||||||
|
__type *bp, *bq; \
|
||||||
|
__type *p, *q, *r = 0; /* _r_ is potentially the new root */ \
|
||||||
|
int i, which = 0, top, b1, path_len; \
|
||||||
|
unsigned cnt = 0; \
|
||||||
|
bp = *root_, bq = 0; \
|
||||||
|
/* find the insertion location */ \
|
||||||
|
for (p = bp, q = bq, top = path_len = 0; p; q = p, p = p->__head.p[which]) { \
|
||||||
|
int cmp; \
|
||||||
|
cmp = __cmp(x, p); \
|
||||||
|
if (cmp >= 0) cnt += krmq_size_child(__head, p, 0) + 1; \
|
||||||
|
if (cmp == 0) { \
|
||||||
|
if (cnt_) *cnt_ = cnt; \
|
||||||
|
return p; \
|
||||||
|
} \
|
||||||
|
if (p->__head.balance != 0) \
|
||||||
|
bq = q, bp = p, top = 0; \
|
||||||
|
stack[top++] = which = (cmp > 0); \
|
||||||
|
path[path_len++] = p; \
|
||||||
|
} \
|
||||||
|
if (cnt_) *cnt_ = cnt; \
|
||||||
|
x->__head.balance = 0, x->__head.size = 1, x->__head.p[0] = x->__head.p[1] = 0, x->__head.s = x; \
|
||||||
|
if (q == 0) *root_ = x; \
|
||||||
|
else q->__head.p[which] = x; \
|
||||||
|
if (bp == 0) return x; \
|
||||||
|
for (i = 0; i < path_len; ++i) ++path[i]->__head.size; \
|
||||||
|
for (i = path_len - 1; i >= 0; --i) { \
|
||||||
|
krmq_update_min_##suf(path[i], path[i]->__head.p[0], path[i]->__head.p[1]); \
|
||||||
|
if (path[i]->__head.s != x) break; \
|
||||||
|
} \
|
||||||
|
for (p = bp, top = 0; p != x; p = p->__head.p[stack[top]], ++top) /* update balance factors */ \
|
||||||
|
if (stack[top] == 0) --p->__head.balance; \
|
||||||
|
else ++p->__head.balance; \
|
||||||
|
if (bp->__head.balance > -2 && bp->__head.balance < 2) return x; /* no re-balance needed */ \
|
||||||
|
/* re-balance */ \
|
||||||
|
which = (bp->__head.balance < 0); \
|
||||||
|
b1 = which == 0? +1 : -1; \
|
||||||
|
q = bp->__head.p[1 - which]; \
|
||||||
|
if (q->__head.balance == b1) { \
|
||||||
|
r = krmq_rotate1_##suf(bp, which); \
|
||||||
|
q->__head.balance = bp->__head.balance = 0; \
|
||||||
|
} else r = krmq_rotate2_##suf(bp, which); \
|
||||||
|
if (bq == 0) *root_ = r; \
|
||||||
|
else bq->__head.p[bp != bq->__head.p[0]] = r; \
|
||||||
|
return x; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __KRMQ_ERASE(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__scope __type *krmq_erase_##suf(__type **root_, const __type *x, unsigned *cnt_) { \
|
||||||
|
__type *p, *path[KRMQ_MAX_DEPTH], fake; \
|
||||||
|
unsigned char dir[KRMQ_MAX_DEPTH]; \
|
||||||
|
int i, d = 0, cmp; \
|
||||||
|
unsigned cnt = 0; \
|
||||||
|
fake = **root_, fake.__head.p[0] = *root_, fake.__head.p[1] = 0; \
|
||||||
|
if (cnt_) *cnt_ = 0; \
|
||||||
|
if (x) { \
|
||||||
|
for (cmp = -1, p = &fake; cmp; cmp = __cmp(x, p)) { \
|
||||||
|
int which = (cmp > 0); \
|
||||||
|
if (cmp > 0) cnt += krmq_size_child(__head, p, 0) + 1; \
|
||||||
|
dir[d] = which; \
|
||||||
|
path[d++] = p; \
|
||||||
|
p = p->__head.p[which]; \
|
||||||
|
if (p == 0) { \
|
||||||
|
if (cnt_) *cnt_ = 0; \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
cnt += krmq_size_child(__head, p, 0) + 1; /* because p==x is not counted */ \
|
||||||
|
} else { \
|
||||||
|
for (p = &fake, cnt = 1; p; p = p->__head.p[0]) \
|
||||||
|
dir[d] = 0, path[d++] = p; \
|
||||||
|
p = path[--d]; \
|
||||||
|
} \
|
||||||
|
if (cnt_) *cnt_ = cnt; \
|
||||||
|
for (i = 1; i < d; ++i) --path[i]->__head.size; \
|
||||||
|
if (p->__head.p[1] == 0) { /* ((1,.)2,3)4 => (1,3)4; p=2 */ \
|
||||||
|
path[d-1]->__head.p[dir[d-1]] = p->__head.p[0]; \
|
||||||
|
} else { \
|
||||||
|
__type *q = p->__head.p[1]; \
|
||||||
|
if (q->__head.p[0] == 0) { /* ((1,2)3,4)5 => ((1)2,4)5; p=3,q=2 */ \
|
||||||
|
q->__head.p[0] = p->__head.p[0]; \
|
||||||
|
q->__head.balance = p->__head.balance; \
|
||||||
|
path[d-1]->__head.p[dir[d-1]] = q; \
|
||||||
|
path[d] = q, dir[d++] = 1; \
|
||||||
|
q->__head.size = p->__head.size - 1; \
|
||||||
|
} else { /* ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6 */ \
|
||||||
|
__type *r; \
|
||||||
|
int e = d++; /* backup _d_ */\
|
||||||
|
for (;;) { \
|
||||||
|
dir[d] = 0; \
|
||||||
|
path[d++] = q; \
|
||||||
|
r = q->__head.p[0]; \
|
||||||
|
if (r->__head.p[0] == 0) break; \
|
||||||
|
q = r; \
|
||||||
|
} \
|
||||||
|
r->__head.p[0] = p->__head.p[0]; \
|
||||||
|
q->__head.p[0] = r->__head.p[1]; \
|
||||||
|
r->__head.p[1] = p->__head.p[1]; \
|
||||||
|
r->__head.balance = p->__head.balance; \
|
||||||
|
path[e-1]->__head.p[dir[e-1]] = r; \
|
||||||
|
path[e] = r, dir[e] = 1; \
|
||||||
|
for (i = e + 1; i < d; ++i) --path[i]->__head.size; \
|
||||||
|
r->__head.size = p->__head.size - 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
for (i = d - 1; i >= 0; --i) /* not sure why adding condition "path[i]->__head.s==p" doesn't work */ \
|
||||||
|
krmq_update_min_##suf(path[i], path[i]->__head.p[0], path[i]->__head.p[1]); \
|
||||||
|
while (--d > 0) { \
|
||||||
|
__type *q = path[d]; \
|
||||||
|
int which, other, b1 = 1, b2 = 2; \
|
||||||
|
which = dir[d], other = 1 - which; \
|
||||||
|
if (which) b1 = -b1, b2 = -b2; \
|
||||||
|
q->__head.balance += b1; \
|
||||||
|
if (q->__head.balance == b1) break; \
|
||||||
|
else if (q->__head.balance == b2) { \
|
||||||
|
__type *r = q->__head.p[other]; \
|
||||||
|
if (r->__head.balance == -b1) { \
|
||||||
|
path[d-1]->__head.p[dir[d-1]] = krmq_rotate2_##suf(q, which); \
|
||||||
|
} else { \
|
||||||
|
path[d-1]->__head.p[dir[d-1]] = krmq_rotate1_##suf(q, which); \
|
||||||
|
if (r->__head.balance == 0) { \
|
||||||
|
r->__head.balance = -b1; \
|
||||||
|
q->__head.balance = b1; \
|
||||||
|
break; \
|
||||||
|
} else r->__head.balance = q->__head.balance = 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
*root_ = fake.__head.p[0]; \
|
||||||
|
return p; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define krmq_free(__type, __head, __root, __free) do { \
|
||||||
|
__type *_p, *_q; \
|
||||||
|
for (_p = __root; _p; _p = _q) { \
|
||||||
|
if (_p->__head.p[0] == 0) { \
|
||||||
|
_q = _p->__head.p[1]; \
|
||||||
|
__free(_p); \
|
||||||
|
} else { \
|
||||||
|
_q = _p->__head.p[0]; \
|
||||||
|
_p->__head.p[0] = _q->__head.p[1]; \
|
||||||
|
_q->__head.p[1] = _p; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define __KRMQ_ITR(suf, __scope, __type, __head, __cmp) \
|
||||||
|
struct krmq_itr_##suf { \
|
||||||
|
const __type *stack[KRMQ_MAX_DEPTH], **top; \
|
||||||
|
}; \
|
||||||
|
__scope void krmq_itr_first_##suf(const __type *root, struct krmq_itr_##suf *itr) { \
|
||||||
|
const __type *p; \
|
||||||
|
for (itr->top = itr->stack - 1, p = root; p; p = p->__head.p[0]) \
|
||||||
|
*++itr->top = p; \
|
||||||
|
} \
|
||||||
|
__scope int krmq_itr_find_##suf(const __type *root, const __type *x, struct krmq_itr_##suf *itr) { \
|
||||||
|
const __type *p = root; \
|
||||||
|
itr->top = itr->stack - 1; \
|
||||||
|
while (p != 0) { \
|
||||||
|
int cmp; \
|
||||||
|
*++itr->top = p; \
|
||||||
|
cmp = __cmp(x, p); \
|
||||||
|
if (cmp < 0) p = p->__head.p[0]; \
|
||||||
|
else if (cmp > 0) p = p->__head.p[1]; \
|
||||||
|
else break; \
|
||||||
|
} \
|
||||||
|
return p? 1 : 0; \
|
||||||
|
} \
|
||||||
|
__scope int krmq_itr_next_bidir_##suf(struct krmq_itr_##suf *itr, int dir) { \
|
||||||
|
const __type *p; \
|
||||||
|
if (itr->top < itr->stack) return 0; \
|
||||||
|
dir = !!dir; \
|
||||||
|
p = (*itr->top)->__head.p[dir]; \
|
||||||
|
if (p) { /* go down */ \
|
||||||
|
for (; p; p = p->__head.p[!dir]) \
|
||||||
|
*++itr->top = p; \
|
||||||
|
return 1; \
|
||||||
|
} else { /* go up */ \
|
||||||
|
do { \
|
||||||
|
p = *itr->top--; \
|
||||||
|
} while (itr->top >= itr->stack && p == (*itr->top)->__head.p[dir]); \
|
||||||
|
return itr->top < itr->stack? 0 : 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a node to the tree
|
||||||
|
*
|
||||||
|
* @param suf name suffix used in KRMQ_INIT()
|
||||||
|
* @param proot pointer to the root of the tree (in/out: root may change)
|
||||||
|
* @param x node to insert (in)
|
||||||
|
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
|
||||||
|
*
|
||||||
|
* @return _x_ if not present in the tree, or the node equal to x.
|
||||||
|
*/
|
||||||
|
#define krmq_insert(suf, proot, x, cnt) krmq_insert_##suf(proot, x, cnt)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a node in the tree
|
||||||
|
*
|
||||||
|
* @param suf name suffix used in KRMQ_INIT()
|
||||||
|
* @param root root of the tree
|
||||||
|
* @param x node value to find (in)
|
||||||
|
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
|
||||||
|
*
|
||||||
|
* @return node equal to _x_ if present, or NULL if absent
|
||||||
|
*/
|
||||||
|
#define krmq_find(suf, root, x, cnt) krmq_find_##suf(root, x, cnt)
|
||||||
|
#define krmq_interval(suf, root, x, lower, upper) krmq_interval_##suf(root, x, lower, upper)
|
||||||
|
#define krmq_rmq(suf, root, lo, up) krmq_rmq_##suf(root, lo, up)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a node from the tree
|
||||||
|
*
|
||||||
|
* @param suf name suffix used in KRMQ_INIT()
|
||||||
|
* @param proot pointer to the root of the tree (in/out: root may change)
|
||||||
|
* @param x node value to delete; if NULL, delete the first node (in)
|
||||||
|
*
|
||||||
|
* @return node removed from the tree if present, or NULL if absent
|
||||||
|
*/
|
||||||
|
#define krmq_erase(suf, proot, x, cnt) krmq_erase_##suf(proot, x, cnt)
|
||||||
|
#define krmq_erase_first(suf, proot) krmq_erase_##suf(proot, 0, 0)
|
||||||
|
|
||||||
|
#define krmq_itr_t(suf) struct krmq_itr_##suf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place the iterator at the smallest object
|
||||||
|
*
|
||||||
|
* @param suf name suffix used in KRMQ_INIT()
|
||||||
|
* @param root root of the tree
|
||||||
|
* @param itr iterator
|
||||||
|
*/
|
||||||
|
#define krmq_itr_first(suf, root, itr) krmq_itr_first_##suf(root, itr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place the iterator at the object equal to or greater than the query
|
||||||
|
*
|
||||||
|
* @param suf name suffix used in KRMQ_INIT()
|
||||||
|
* @param root root of the tree
|
||||||
|
* @param x query (in)
|
||||||
|
* @param itr iterator (out)
|
||||||
|
*
|
||||||
|
* @return 1 if find; 0 otherwise. krmq_at(itr) is NULL if and only if query is
|
||||||
|
* larger than all objects in the tree
|
||||||
|
*/
|
||||||
|
#define krmq_itr_find(suf, root, x, itr) krmq_itr_find_##suf(root, x, itr)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move to the next object in order
|
||||||
|
*
|
||||||
|
* @param itr iterator (modified)
|
||||||
|
*
|
||||||
|
* @return 1 if there is a next object; 0 otherwise
|
||||||
|
*/
|
||||||
|
#define krmq_itr_next(suf, itr) krmq_itr_next_bidir_##suf(itr, 1)
|
||||||
|
#define krmq_itr_prev(suf, itr) krmq_itr_next_bidir_##suf(itr, 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the pointer at the iterator
|
||||||
|
*
|
||||||
|
* @param itr iterator
|
||||||
|
*
|
||||||
|
* @return pointer if present; NULL otherwise
|
||||||
|
*/
|
||||||
|
#define krmq_at(itr) ((itr)->top < (itr)->stack? 0 : *(itr)->top)
|
||||||
|
|
||||||
|
#define KRMQ_INIT2(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__KRMQ_FIND(suf, __scope, __type, __head, __cmp) \
|
||||||
|
__KRMQ_RMQ(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__KRMQ_ROTATE(suf, __type, __head, __lt2) \
|
||||||
|
__KRMQ_INSERT(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__KRMQ_ERASE(suf, __scope, __type, __head, __cmp, __lt2) \
|
||||||
|
__KRMQ_ITR(suf, __scope, __type, __head, __cmp)
|
||||||
|
|
||||||
|
#define KRMQ_INIT(suf, __type, __head, __cmp, __lt2) \
|
||||||
|
KRMQ_INIT2(suf,, __type, __head, __cmp, __lt2)
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -89,7 +89,7 @@
|
|||||||
#ifndef KSTRING_T
|
#ifndef KSTRING_T
|
||||||
#define KSTRING_T kstring_t
|
#define KSTRING_T kstring_t
|
||||||
typedef struct __kstring_t {
|
typedef struct __kstring_t {
|
||||||
unsigned l, m;
|
size_t l, m;
|
||||||
char *s;
|
char *s;
|
||||||
} kstring_t;
|
} kstring_t;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ typedef struct {
|
|||||||
int depth;
|
int depth;
|
||||||
} ks_isort_stack_t;
|
} ks_isort_stack_t;
|
||||||
|
|
||||||
#define KSORT_SWAP(type_t, a, b) { register type_t t=(a); (a)=(b); (b)=t; }
|
#define KSORT_SWAP(type_t, a, b) { 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[]) \
|
void ks_heapdown_##name(size_t i, size_t n, type_t l[]) \
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
#define KSW_EZ_SPLICE_REV 0x200
|
#define KSW_EZ_SPLICE_REV 0x200
|
||||||
#define KSW_EZ_SPLICE_FLANK 0x400
|
#define KSW_EZ_SPLICE_FLANK 0x400
|
||||||
|
|
||||||
|
// The subset of CIGAR operators used by ksw code.
|
||||||
|
// Use MM_CIGAR_* from minimap.h if you need the full list.
|
||||||
|
#define KSW_CIGAR_MATCH 0
|
||||||
|
#define KSW_CIGAR_INS 1
|
||||||
|
#define KSW_CIGAR_DEL 2
|
||||||
|
#define KSW_CIGAR_N_SKIP 3
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -58,10 +65,10 @@ void ksw_extd(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t
|
|||||||
int8_t gapo, int8_t gape, int8_t gapo2, int8_t gape2, int w, int zdrop, int flag, ksw_extz_t *ez);
|
int8_t gapo, int8_t gape, int8_t gapo2, int8_t gape2, int w, int zdrop, int flag, ksw_extz_t *ez);
|
||||||
|
|
||||||
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t gapo, int8_t gape, int8_t gapo2, int8_t gape2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez);
|
int8_t gapo, int8_t gape, int8_t gapo2, int8_t gape2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
||||||
|
|
||||||
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t gapo, int8_t gape, int8_t gapo2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez);
|
int8_t gapo, int8_t gape, int8_t gapo2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez);
|
||||||
|
|
||||||
void ksw_extf2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t mch, int8_t mis, int8_t e, int w, int xdrop, ksw_extz_t *ez);
|
void ksw_extf2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t mch, int8_t mis, int8_t e, int w, int xdrop, ksw_extz_t *ez);
|
||||||
|
|
||||||
@@ -137,13 +144,13 @@ static inline void ksw_backtrack(void *km, int is_rot, int is_rev, int min_intro
|
|||||||
else if (!(tmp >> (state + 2) & 1)) state = 0; // if requesting other states, _state_ stays the same if it is a continuation; otherwise, set to H
|
else if (!(tmp >> (state + 2) & 1)) state = 0; // if requesting other states, _state_ stays the same if it is a continuation; otherwise, set to H
|
||||||
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, KSW_CIGAR_MATCH, 1), --i, --j;
|
||||||
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 == 1 || (state == 3 && min_intron_len <= 0)) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, KSW_CIGAR_DEL, 1), --i;
|
||||||
else if (state == 3 && min_intron_len > 0) 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, KSW_CIGAR_N_SKIP, 1), --i;
|
||||||
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, KSW_CIGAR_INS, 1), --j;
|
||||||
}
|
}
|
||||||
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 (i >= 0) cigar = ksw_push_cigar(km, &n_cigar, &m_cigar, cigar, min_intron_len > 0 && i >= min_intron_len? KSW_CIGAR_N_SKIP : KSW_CIGAR_DEL, 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, KSW_CIGAR_INS, 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
|
||||||
tmp = cigar[i], cigar[i] = cigar[n_cigar-1-i], cigar[n_cigar-1-i] = tmp;
|
tmp = cigar[i], cigar[i] = cigar[n_cigar-1-i], cigar[n_cigar-1-i] = tmp;
|
||||||
|
|||||||
+24
-25
@@ -17,18 +17,20 @@
|
|||||||
void __cpuidex(int cpuid[4], int func_id, int subfunc_id)
|
void __cpuidex(int cpuid[4], int func_id, int subfunc_id)
|
||||||
{
|
{
|
||||||
#if defined(__x86_64__)
|
#if defined(__x86_64__)
|
||||||
asm volatile ("cpuid"
|
__asm__ volatile ("cpuid"
|
||||||
: "=a" (cpuid[0]), "=b" (cpuid[1]), "=c" (cpuid[2]), "=d" (cpuid[3])
|
: "=a" (cpuid[0]), "=b" (cpuid[1]), "=c" (cpuid[2]), "=d" (cpuid[3])
|
||||||
: "0" (func_id), "2" (subfunc_id));
|
: "0" (func_id), "2" (subfunc_id));
|
||||||
#else // on 32bit, ebx can NOT be used as PIC code
|
#else // on 32bit, ebx can NOT be used as PIC code
|
||||||
asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
|
__asm__ volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
|
||||||
: "=a" (cpuid[0]), "=r" (cpuid[1]), "=c" (cpuid[2]), "=d" (cpuid[3])
|
: "=a" (cpuid[0]), "=r" (cpuid[1]), "=c" (cpuid[2]), "=d" (cpuid[3])
|
||||||
: "0" (func_id), "2" (subfunc_id));
|
: "0" (func_id), "2" (subfunc_id));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int x86_simd(void)
|
static int ksw_simd = -1;
|
||||||
|
|
||||||
|
static int x86_simd(void)
|
||||||
{
|
{
|
||||||
int flag = 0, cpuid[4], max_id;
|
int flag = 0, cpuid[4], max_id;
|
||||||
__cpuidex(cpuid, 0, 0);
|
__cpuidex(cpuid, 0, 0);
|
||||||
@@ -54,44 +56,41 @@ void ksw_extz2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
{
|
{
|
||||||
extern void ksw_extz2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat, int8_t q, int8_t e, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
extern void ksw_extz2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat, int8_t q, int8_t e, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
||||||
extern void ksw_extz2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat, int8_t q, int8_t e, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
extern void ksw_extz2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat, int8_t q, int8_t e, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
||||||
unsigned simd;
|
if (ksw_simd < 0) ksw_simd = x86_simd();
|
||||||
simd = x86_simd();
|
if (ksw_simd & SIMD_SSE4_1)
|
||||||
if (simd & SIMD_SSE4_1)
|
|
||||||
ksw_extz2_sse41(km, qlen, query, tlen, target, m, mat, q, e, w, zdrop, end_bonus, flag, ez);
|
ksw_extz2_sse41(km, qlen, query, tlen, target, m, mat, q, e, w, zdrop, end_bonus, flag, ez);
|
||||||
else if (simd & SIMD_SSE2)
|
else if (ksw_simd & SIMD_SSE2)
|
||||||
ksw_extz2_sse2(km, qlen, query, tlen, target, m, mat, q, e, w, zdrop, end_bonus, flag, ez);
|
ksw_extz2_sse2(km, qlen, query, tlen, target, m, mat, q, e, w, zdrop, end_bonus, flag, ez);
|
||||||
else abort();
|
else abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez)
|
||||||
{
|
{
|
||||||
extern void ksw_extd2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
extern void ksw_extd2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez);
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
||||||
extern void ksw_extd2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
extern void ksw_extd2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez);
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez);
|
||||||
unsigned simd;
|
if (ksw_simd < 0) ksw_simd = x86_simd();
|
||||||
simd = x86_simd();
|
if (ksw_simd & SIMD_SSE4_1)
|
||||||
if (simd & SIMD_SSE4_1)
|
ksw_extd2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, ez);
|
||||||
ksw_extd2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, qd, ez);
|
else if (ksw_simd & SIMD_SSE2)
|
||||||
else if (simd & SIMD_SSE2)
|
ksw_extd2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, ez);
|
||||||
ksw_extd2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, qd, ez);
|
|
||||||
else abort();
|
else abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez)
|
||||||
{
|
{
|
||||||
extern void ksw_exts2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
extern void ksw_exts2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez);
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez);
|
||||||
extern void ksw_exts2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
extern void ksw_exts2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez);
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez);
|
||||||
unsigned simd;
|
if (ksw_simd < 0) ksw_simd = x86_simd();
|
||||||
simd = x86_simd();
|
if (ksw_simd & SIMD_SSE4_1)
|
||||||
if (simd & SIMD_SSE4_1)
|
ksw_exts2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, junc_bonus, flag, junc, ez);
|
||||||
ksw_exts2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, flag, ez);
|
else if (ksw_simd & SIMD_SSE2)
|
||||||
else if (simd & SIMD_SSE2)
|
ksw_exts2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, junc_bonus, flag, junc, ez);
|
||||||
ksw_exts2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, flag, ez);
|
|
||||||
else abort();
|
else abort();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+37
-40
@@ -4,31 +4,38 @@
|
|||||||
#include "ksw2.h"
|
#include "ksw2.h"
|
||||||
|
|
||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse2.h>
|
||||||
|
#else
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KSW_SSE2_ONLY
|
#ifdef KSW_SSE2_ONLY
|
||||||
#undef __SSE4_1__
|
#undef __SSE4_1__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse4.1.h>
|
||||||
|
#else
|
||||||
#include <smmintrin.h>
|
#include <smmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KSW_CPU_DISPATCH
|
#ifdef KSW_CPU_DISPATCH
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
void ksw_extd2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_extd2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez)
|
||||||
#else
|
#else
|
||||||
void ksw_extd2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_extd2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, const int8_t *qd, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t e2, int w, int zdrop, int end_bonus, int flag, ksw_extz_t *ez)
|
||||||
#endif // ~KSW_CPU_DISPATCH
|
#endif // ~KSW_CPU_DISPATCH
|
||||||
{
|
{
|
||||||
#define __dp_code_block1 \
|
#define __dp_code_block1 \
|
||||||
dt = _mm_load_si128(&dv[t]); \
|
|
||||||
z = _mm_load_si128(&s[t]); \
|
z = _mm_load_si128(&s[t]); \
|
||||||
xt1 = _mm_load_si128(&x[t]); /* xt1 <- x[r-1][t..t+15] */ \
|
xt1 = _mm_load_si128(&x[t]); /* xt1 <- x[r-1][t..t+15] */ \
|
||||||
tmp = _mm_srli_si128(xt1, 15); /* tmp <- x[r-1][t+15] */ \
|
tmp = _mm_srli_si128(xt1, 15); /* tmp <- x[r-1][t+15] */ \
|
||||||
@@ -51,10 +58,10 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
#define __dp_code_block2 \
|
#define __dp_code_block2 \
|
||||||
_mm_store_si128(&u[t], _mm_sub_epi8(z, vt1)); /* u[r][t..t+15] <- z - v[r-1][t-1..t+14] */ \
|
_mm_store_si128(&u[t], _mm_sub_epi8(z, vt1)); /* u[r][t..t+15] <- z - v[r-1][t-1..t+14] */ \
|
||||||
_mm_store_si128(&v[t], _mm_sub_epi8(z, ut)); /* v[r][t..t+15] <- z - u[r-1][t..t+15] */ \
|
_mm_store_si128(&v[t], _mm_sub_epi8(z, ut)); /* v[r][t..t+15] <- z - u[r-1][t..t+15] */ \
|
||||||
tmp = _mm_sub_epi8(z, _mm_add_epi8(dt, q_)); \
|
tmp = _mm_sub_epi8(z, q_); \
|
||||||
a = _mm_sub_epi8(a, tmp); \
|
a = _mm_sub_epi8(a, tmp); \
|
||||||
b = _mm_sub_epi8(b, tmp); \
|
b = _mm_sub_epi8(b, tmp); \
|
||||||
tmp = _mm_sub_epi8(z, _mm_add_epi8(dt, q2_)); \
|
tmp = _mm_sub_epi8(z, q2_); \
|
||||||
a2= _mm_sub_epi8(a2, tmp); \
|
a2= _mm_sub_epi8(a2, tmp); \
|
||||||
b2= _mm_sub_epi8(b2, tmp);
|
b2= _mm_sub_epi8(b2, tmp);
|
||||||
|
|
||||||
@@ -62,8 +69,8 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
int with_cigar = !(flag&KSW_EZ_SCORE_ONLY), approx_max = !!(flag&KSW_EZ_APPROX_MAX);
|
int with_cigar = !(flag&KSW_EZ_SCORE_ONLY), approx_max = !!(flag&KSW_EZ_APPROX_MAX);
|
||||||
int32_t *H = 0, H0 = 0, last_H0_t = 0;
|
int32_t *H = 0, H0 = 0, last_H0_t = 0;
|
||||||
uint8_t *qr, *sf, *mem, *mem2 = 0;
|
uint8_t *qr, *sf, *mem, *mem2 = 0;
|
||||||
__m128i q_, q2_, qe_, qe2_, e_, e2_, zero_, sc_mch_, sc_mis_, m1_, sc_N_;
|
__m128i q_, q2_, qe_, qe2_, zero_, sc_mch_, sc_mis_, m1_, sc_N_;
|
||||||
__m128i *u, *v, *x, *y, *x2, *y2, *s, *p = 0, *dv;
|
__m128i *u, *v, *x, *y, *x2, *y2, *s, *p = 0;
|
||||||
|
|
||||||
ksw_reset_extz(ez);
|
ksw_reset_extz(ez);
|
||||||
if (m <= 1 || qlen <= 0 || tlen <= 0) return;
|
if (m <= 1 || qlen <= 0 || tlen <= 0) return;
|
||||||
@@ -73,8 +80,6 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
zero_ = _mm_set1_epi8(0);
|
zero_ = _mm_set1_epi8(0);
|
||||||
q_ = _mm_set1_epi8(q);
|
q_ = _mm_set1_epi8(q);
|
||||||
q2_ = _mm_set1_epi8(q2);
|
q2_ = _mm_set1_epi8(q2);
|
||||||
e_ = _mm_set1_epi8(e);
|
|
||||||
e2_ = _mm_set1_epi8(e2);
|
|
||||||
qe_ = _mm_set1_epi8(q + e);
|
qe_ = _mm_set1_epi8(q + e);
|
||||||
qe2_ = _mm_set1_epi8(q2 + e2);
|
qe2_ = _mm_set1_epi8(q2 + e2);
|
||||||
sc_mch_ = _mm_set1_epi8(mat[0]);
|
sc_mch_ = _mm_set1_epi8(mat[0]);
|
||||||
@@ -99,23 +104,16 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
++long_thres;
|
++long_thres;
|
||||||
long_diff = long_thres * (e - e2) - (q2 - q) - e2;
|
long_diff = long_thres * (e - e2) - (q2 - q) - e2;
|
||||||
|
|
||||||
mem = (uint8_t*)kcalloc(km, tlen_ * 9 + qlen_ + 1, 16);
|
mem = (uint8_t*)kcalloc(km, tlen_ * 8 + qlen_ + 1, 16);
|
||||||
u = (__m128i*)(((size_t)mem + 15) >> 4 << 4); // 16-byte aligned
|
u = (__m128i*)(((size_t)mem + 15) >> 4 << 4); // 16-byte aligned
|
||||||
v = u + tlen_, x = v + tlen_, y = x + tlen_, x2 = y + tlen_, y2 = x2 + tlen_, dv = y2 + tlen_;
|
v = u + tlen_, x = v + tlen_, y = x + tlen_, x2 = y + tlen_, y2 = x2 + tlen_;
|
||||||
s = dv + tlen_, sf = (uint8_t*)(s + tlen_), qr = sf + tlen_ * 16;
|
s = y2 + tlen_, sf = (uint8_t*)(s + tlen_), qr = sf + tlen_ * 16;
|
||||||
memset(u, -q - e, tlen_ * 16);
|
memset(u, -q - e, tlen_ * 16);
|
||||||
memset(v, -q - e, tlen_ * 16);
|
memset(v, -q - e, tlen_ * 16);
|
||||||
memset(x, -q - e, tlen_ * 16);
|
memset(x, -q - e, tlen_ * 16);
|
||||||
memset(y, -q - e, tlen_ * 16);
|
memset(y, -q - e, tlen_ * 16);
|
||||||
memset(x2, -q2 - e2, tlen_ * 16);
|
memset(x2, -q2 - e2, tlen_ * 16);
|
||||||
memset(y2, -q2 - e2, tlen_ * 16);
|
memset(y2, -q2 - e2, tlen_ * 16);
|
||||||
if (qd) {
|
|
||||||
int8_t *tmp = (int8_t*)dv;
|
|
||||||
for (t = 0; t < tlen; ++t) tmp[t] = -qd[t];
|
|
||||||
fprintf(stderr, "%d\t%d\t%x\n", tlen, qlen, flag&KSW_EZ_RIGHT);
|
|
||||||
for (t = 0; t < tlen; ++t) fputc("ACGTN"[target[t]], stderr); fputc('\n', stderr);
|
|
||||||
for (t = 0; t < tlen; ++t) fputc('0' + qd[t], stderr); fputc('\n', stderr);
|
|
||||||
}
|
|
||||||
if (!approx_max) {
|
if (!approx_max) {
|
||||||
H = (int32_t*)kmalloc(km, tlen_ * 16 * 4);
|
H = (int32_t*)kmalloc(km, tlen_ * 16 * 4);
|
||||||
for (t = 0; t < tlen_ * 16; ++t) H[t] = KSW_NEG_INF;
|
for (t = 0; t < tlen_ * 16; ++t) H[t] = KSW_NEG_INF;
|
||||||
@@ -192,7 +190,7 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
assert(en_ - st_ + 1 <= n_col_);
|
assert(en_ - st_ + 1 <= n_col_);
|
||||||
if (!with_cigar) { // score only
|
if (!with_cigar) { // score only
|
||||||
for (t = st_; t <= en_; ++t) {
|
for (t = st_; t <= en_; ++t) {
|
||||||
__m128i z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp, dt;
|
__m128i z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp;
|
||||||
__dp_code_block1;
|
__dp_code_block1;
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
z = _mm_max_epi8(z, a);
|
z = _mm_max_epi8(z, a);
|
||||||
@@ -201,10 +199,10 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
z = _mm_max_epi8(z, b2);
|
z = _mm_max_epi8(z, b2);
|
||||||
z = _mm_min_epi8(z, sc_mch_);
|
z = _mm_min_epi8(z, sc_mch_);
|
||||||
__dp_code_block2; // save u[] and v[]; update a, b, a2 and b2
|
__dp_code_block2; // save u[] and v[]; update a, b, a2 and b2
|
||||||
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_max_epi8(a, zero_), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_max_epi8(a, zero_), qe_));
|
||||||
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_max_epi8(b, zero_), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_max_epi8(b, zero_), qe_));
|
||||||
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_max_epi8(a2, zero_), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_max_epi8(a2, zero_), qe2_));
|
||||||
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_max_epi8(b2, zero_), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_max_epi8(b2, zero_), qe2_));
|
||||||
#else
|
#else
|
||||||
tmp = _mm_cmpgt_epi8(a, z);
|
tmp = _mm_cmpgt_epi8(a, z);
|
||||||
z = _mm_or_si128(_mm_andnot_si128(tmp, z), _mm_and_si128(tmp, a));
|
z = _mm_or_si128(_mm_andnot_si128(tmp, z), _mm_and_si128(tmp, a));
|
||||||
@@ -218,20 +216,20 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
z = _mm_or_si128(_mm_and_si128(tmp, sc_mch_), _mm_andnot_si128(tmp, z));
|
z = _mm_or_si128(_mm_and_si128(tmp, sc_mch_), _mm_andnot_si128(tmp, z));
|
||||||
__dp_code_block2;
|
__dp_code_block2;
|
||||||
tmp = _mm_cmpgt_epi8(a, zero_);
|
tmp = _mm_cmpgt_epi8(a, zero_);
|
||||||
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_and_si128(tmp, a), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_and_si128(tmp, a), qe_));
|
||||||
tmp = _mm_cmpgt_epi8(b, zero_);
|
tmp = _mm_cmpgt_epi8(b, zero_);
|
||||||
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_and_si128(tmp, b), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_and_si128(tmp, b), qe_));
|
||||||
tmp = _mm_cmpgt_epi8(a2, zero_);
|
tmp = _mm_cmpgt_epi8(a2, zero_);
|
||||||
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_and_si128(tmp, a2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_and_si128(tmp, a2), qe2_));
|
||||||
tmp = _mm_cmpgt_epi8(b2, zero_);
|
tmp = _mm_cmpgt_epi8(b2, zero_);
|
||||||
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_and_si128(tmp, b2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_and_si128(tmp, b2), qe2_));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} else if (!(flag&KSW_EZ_RIGHT)) { // gap left-alignment
|
} else if (!(flag&KSW_EZ_RIGHT)) { // gap left-alignment
|
||||||
__m128i *pr = p + (size_t)r * n_col_ - st_;
|
__m128i *pr = p + (size_t)r * n_col_ - st_;
|
||||||
off[r] = st, off_end[r] = en;
|
off[r] = st, off_end[r] = en;
|
||||||
for (t = st_; t <= en_; ++t) {
|
for (t = st_; t <= en_; ++t) {
|
||||||
__m128i d, z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp, dt;
|
__m128i d, z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp;
|
||||||
__dp_code_block1;
|
__dp_code_block1;
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
d = _mm_and_si128(_mm_cmpgt_epi8(a, z), _mm_set1_epi8(1)); // d = a > z? 1 : 0
|
d = _mm_and_si128(_mm_cmpgt_epi8(a, z), _mm_set1_epi8(1)); // d = a > z? 1 : 0
|
||||||
@@ -261,16 +259,16 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
#endif
|
#endif
|
||||||
__dp_code_block2;
|
__dp_code_block2;
|
||||||
tmp = _mm_cmpgt_epi8(a, zero_);
|
tmp = _mm_cmpgt_epi8(a, zero_);
|
||||||
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_and_si128(tmp, a), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_and_si128(tmp, a), qe_));
|
||||||
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x08))); // d = a > 0? 1<<3 : 0
|
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x08))); // d = a > 0? 1<<3 : 0
|
||||||
tmp = _mm_cmpgt_epi8(b, zero_);
|
tmp = _mm_cmpgt_epi8(b, zero_);
|
||||||
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_and_si128(tmp, b), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_and_si128(tmp, b), qe_));
|
||||||
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x10))); // d = b > 0? 1<<4 : 0
|
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x10))); // d = b > 0? 1<<4 : 0
|
||||||
tmp = _mm_cmpgt_epi8(a2, zero_);
|
tmp = _mm_cmpgt_epi8(a2, zero_);
|
||||||
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_and_si128(tmp, a2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_and_si128(tmp, a2), qe2_));
|
||||||
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x20))); // d = a > 0? 1<<5 : 0
|
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x20))); // d = a > 0? 1<<5 : 0
|
||||||
tmp = _mm_cmpgt_epi8(b2, zero_);
|
tmp = _mm_cmpgt_epi8(b2, zero_);
|
||||||
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_and_si128(tmp, b2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_and_si128(tmp, b2), qe2_));
|
||||||
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x40))); // d = b > 0? 1<<6 : 0
|
d = _mm_or_si128(d, _mm_and_si128(tmp, _mm_set1_epi8(0x40))); // d = b > 0? 1<<6 : 0
|
||||||
_mm_store_si128(&pr[t], d);
|
_mm_store_si128(&pr[t], d);
|
||||||
}
|
}
|
||||||
@@ -278,7 +276,7 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
__m128i *pr = p + (size_t)r * n_col_ - st_;
|
__m128i *pr = p + (size_t)r * n_col_ - st_;
|
||||||
off[r] = st, off_end[r] = en;
|
off[r] = st, off_end[r] = en;
|
||||||
for (t = st_; t <= en_; ++t) {
|
for (t = st_; t <= en_; ++t) {
|
||||||
__m128i d, z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp, dt;
|
__m128i d, z, a, b, a2, b2, xt1, x2t1, vt1, ut, tmp;
|
||||||
__dp_code_block1;
|
__dp_code_block1;
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
d = _mm_andnot_si128(_mm_cmpgt_epi8(z, a), _mm_set1_epi8(1)); // d = z > a? 0 : 1
|
d = _mm_andnot_si128(_mm_cmpgt_epi8(z, a), _mm_set1_epi8(1)); // d = z > a? 0 : 1
|
||||||
@@ -308,16 +306,16 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
#endif
|
#endif
|
||||||
__dp_code_block2;
|
__dp_code_block2;
|
||||||
tmp = _mm_cmpgt_epi8(zero_, a);
|
tmp = _mm_cmpgt_epi8(zero_, a);
|
||||||
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_andnot_si128(tmp, a), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&x[t], _mm_sub_epi8(_mm_andnot_si128(tmp, a), qe_));
|
||||||
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x08))); // d = a > 0? 1<<3 : 0
|
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x08))); // d = a > 0? 1<<3 : 0
|
||||||
tmp = _mm_cmpgt_epi8(zero_, b);
|
tmp = _mm_cmpgt_epi8(zero_, b);
|
||||||
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_andnot_si128(tmp, b), _mm_add_epi8(dt, qe_)));
|
_mm_store_si128(&y[t], _mm_sub_epi8(_mm_andnot_si128(tmp, b), qe_));
|
||||||
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x10))); // d = b > 0? 1<<4 : 0
|
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x10))); // d = b > 0? 1<<4 : 0
|
||||||
tmp = _mm_cmpgt_epi8(zero_, a2);
|
tmp = _mm_cmpgt_epi8(zero_, a2);
|
||||||
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_andnot_si128(tmp, a2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&x2[t], _mm_sub_epi8(_mm_andnot_si128(tmp, a2), qe2_));
|
||||||
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x20))); // d = a > 0? 1<<5 : 0
|
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x20))); // d = a > 0? 1<<5 : 0
|
||||||
tmp = _mm_cmpgt_epi8(zero_, b2);
|
tmp = _mm_cmpgt_epi8(zero_, b2);
|
||||||
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_andnot_si128(tmp, b2), _mm_add_epi8(dt, qe2_)));
|
_mm_store_si128(&y2[t], _mm_sub_epi8(_mm_andnot_si128(tmp, b2), qe2_));
|
||||||
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x40))); // d = b > 0? 1<<6 : 0
|
d = _mm_or_si128(d, _mm_andnot_si128(tmp, _mm_set1_epi8(0x40))); // d = b > 0? 1<<6 : 0
|
||||||
_mm_store_si128(&pr[t], d);
|
_mm_store_si128(&pr[t], d);
|
||||||
}
|
}
|
||||||
@@ -386,7 +384,6 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
last_st = st, last_en = en;
|
last_st = st, last_en = en;
|
||||||
//for (t = st0; t <= en0; ++t) printf("(%d,%d)\t(%d,%d,%d,%d)\t%d\n", r, t, ((int8_t*)u)[t], ((int8_t*)v)[t], ((int8_t*)x)[t], ((int8_t*)y)[t], H[t]); // for debugging
|
//for (t = st0; t <= en0; ++t) printf("(%d,%d)\t(%d,%d,%d,%d)\t%d\n", r, t, ((int8_t*)u)[t], ((int8_t*)v)[t], ((int8_t*)x)[t], ((int8_t*)y)[t], H[t]); // for debugging
|
||||||
}
|
}
|
||||||
fprintf(stderr, "score: %d\n", ez->score);
|
|
||||||
kfree(km, mem);
|
kfree(km, mem);
|
||||||
if (!approx_max) kfree(km, H);
|
if (!approx_max) kfree(km, H);
|
||||||
if (with_cigar) { // backtrack
|
if (with_cigar) { // backtrack
|
||||||
|
|||||||
+57
-17
@@ -4,27 +4,34 @@
|
|||||||
#include "ksw2.h"
|
#include "ksw2.h"
|
||||||
|
|
||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse2.h>
|
||||||
|
#else
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
#ifdef KSW_SSE2_ONLY
|
#ifdef KSW_SSE2_ONLY
|
||||||
#undef __SSE4_1__
|
#undef __SSE4_1__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse4.1.h>
|
||||||
|
#else
|
||||||
#include <smmintrin.h>
|
#include <smmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KSW_CPU_DISPATCH
|
#ifdef KSW_CPU_DISPATCH
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
void ksw_exts2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_exts2_sse41(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez)
|
||||||
#else
|
#else
|
||||||
void ksw_exts2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_exts2_sse2(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez)
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uint8_t *target, int8_t m, const int8_t *mat,
|
||||||
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez)
|
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int8_t junc_bonus, int flag, const uint8_t *junc, ksw_extz_t *ez)
|
||||||
#endif // ~KSW_CPU_DISPATCH
|
#endif // ~KSW_CPU_DISPATCH
|
||||||
{
|
{
|
||||||
#define __dp_code_block1 \
|
#define __dp_code_block1 \
|
||||||
@@ -113,20 +120,53 @@ void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
|
|||||||
if (flag & (KSW_EZ_SPLICE_FOR|KSW_EZ_SPLICE_REV)) {
|
if (flag & (KSW_EZ_SPLICE_FOR|KSW_EZ_SPLICE_REV)) {
|
||||||
int semi_cost = flag&KSW_EZ_SPLICE_FLANK? -noncan/2 : 0; // GTr or yAG is worth 0.5 bit; see PMID:18688272
|
int semi_cost = flag&KSW_EZ_SPLICE_FLANK? -noncan/2 : 0; // GTr or yAG is worth 0.5 bit; see PMID:18688272
|
||||||
memset(donor, -noncan, tlen_ * 16);
|
memset(donor, -noncan, tlen_ * 16);
|
||||||
for (t = 0; t < tlen - 4; ++t) {
|
|
||||||
int can_type = 0; // type of canonical site: 0=none, 1=GT/AG only, 2=GTr/yAG
|
|
||||||
if ((flag & KSW_EZ_SPLICE_FOR) && target[t+1] == 2 && target[t+2] == 3) can_type = 1; // GTr...
|
|
||||||
if ((flag & KSW_EZ_SPLICE_REV) && target[t+1] == 1 && target[t+2] == 3) can_type = 1; // CTr...
|
|
||||||
if (can_type && (target[t+3] == 0 || target[t+3] == 2)) can_type = 2;
|
|
||||||
if (can_type) ((int8_t*)donor)[t] = can_type == 2? 0 : semi_cost;
|
|
||||||
}
|
|
||||||
memset(acceptor, -noncan, tlen_ * 16);
|
memset(acceptor, -noncan, tlen_ * 16);
|
||||||
for (t = 2; t < tlen; ++t) {
|
if (!(flag & KSW_EZ_REV_CIGAR)) {
|
||||||
int can_type = 0;
|
for (t = 0; t < tlen - 4; ++t) {
|
||||||
if ((flag & KSW_EZ_SPLICE_FOR) && target[t-1] == 0 && target[t] == 2) can_type = 1; // ...yAG
|
int can_type = 0; // type of canonical site: 0=none, 1=GT/AG only, 2=GTr/yAG
|
||||||
if ((flag & KSW_EZ_SPLICE_REV) && target[t-1] == 0 && target[t] == 1) can_type = 1; // ...yAC
|
if ((flag & KSW_EZ_SPLICE_FOR) && target[t+1] == 2 && target[t+2] == 3) can_type = 1; // GTr...
|
||||||
if (can_type && (target[t-2] == 1 || target[t-2] == 3)) can_type = 2;
|
if ((flag & KSW_EZ_SPLICE_REV) && target[t+1] == 1 && target[t+2] == 3) can_type = 1; // CTr...
|
||||||
if (can_type) ((int8_t*)acceptor)[t] = can_type == 2? 0 : semi_cost;
|
if (can_type && (target[t+3] == 0 || target[t+3] == 2)) can_type = 2;
|
||||||
|
if (can_type) ((int8_t*)donor)[t] = can_type == 2? 0 : semi_cost;
|
||||||
|
}
|
||||||
|
if (junc)
|
||||||
|
for (t = 0; t < tlen - 1; ++t)
|
||||||
|
if (((flag & KSW_EZ_SPLICE_FOR) && (junc[t+1]&1)) || ((flag & KSW_EZ_SPLICE_REV) && (junc[t+1]&8)))
|
||||||
|
((int8_t*)donor)[t] += junc_bonus;
|
||||||
|
for (t = 2; t < tlen; ++t) {
|
||||||
|
int can_type = 0;
|
||||||
|
if ((flag & KSW_EZ_SPLICE_FOR) && target[t-1] == 0 && target[t] == 2) can_type = 1; // ...yAG
|
||||||
|
if ((flag & KSW_EZ_SPLICE_REV) && target[t-1] == 0 && target[t] == 1) can_type = 1; // ...yAC
|
||||||
|
if (can_type && (target[t-2] == 1 || target[t-2] == 3)) can_type = 2;
|
||||||
|
if (can_type) ((int8_t*)acceptor)[t] = can_type == 2? 0 : semi_cost;
|
||||||
|
}
|
||||||
|
if (junc)
|
||||||
|
for (t = 0; t < tlen; ++t)
|
||||||
|
if (((flag & KSW_EZ_SPLICE_FOR) && (junc[t]&2)) || ((flag & KSW_EZ_SPLICE_REV) && (junc[t]&4)))
|
||||||
|
((int8_t*)acceptor)[t] += junc_bonus;
|
||||||
|
} else {
|
||||||
|
for (t = 0; t < tlen - 4; ++t) {
|
||||||
|
int can_type = 0; // type of canonical site: 0=none, 1=GT/AG only, 2=GTr/yAG
|
||||||
|
if ((flag & KSW_EZ_SPLICE_FOR) && target[t+1] == 2 && target[t+2] == 0) can_type = 1; // GAy...
|
||||||
|
if ((flag & KSW_EZ_SPLICE_REV) && target[t+1] == 1 && target[t+2] == 0) can_type = 1; // CAy...
|
||||||
|
if (can_type && (target[t+3] == 1 || target[t+3] == 3)) can_type = 2;
|
||||||
|
if (can_type) ((int8_t*)donor)[t] = can_type == 2? 0 : semi_cost;
|
||||||
|
}
|
||||||
|
if (junc)
|
||||||
|
for (t = 0; t < tlen - 1; ++t)
|
||||||
|
if (((flag & KSW_EZ_SPLICE_FOR) && (junc[t+1]&2)) || ((flag & KSW_EZ_SPLICE_REV) && (junc[t+1]&4)))
|
||||||
|
((int8_t*)donor)[t] += junc_bonus;
|
||||||
|
for (t = 2; t < tlen; ++t) {
|
||||||
|
int can_type = 0;
|
||||||
|
if ((flag & KSW_EZ_SPLICE_FOR) && target[t-1] == 3 && target[t] == 2) can_type = 1; // ...rTG
|
||||||
|
if ((flag & KSW_EZ_SPLICE_REV) && target[t-1] == 3 && target[t] == 1) can_type = 1; // ...rTC
|
||||||
|
if (can_type && (target[t-2] == 0 || target[t-2] == 2)) can_type = 2;
|
||||||
|
if (can_type) ((int8_t*)acceptor)[t] = can_type == 2? 0 : semi_cost;
|
||||||
|
}
|
||||||
|
if (junc)
|
||||||
|
for (t = 0; t < tlen; ++t)
|
||||||
|
if (((flag & KSW_EZ_SPLICE_FOR) && (junc[t]&1)) || ((flag & KSW_EZ_SPLICE_REV) && (junc[t]&8)))
|
||||||
|
((int8_t*)acceptor)[t] += junc_bonus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,23 @@
|
|||||||
#include "ksw2.h"
|
#include "ksw2.h"
|
||||||
|
|
||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse2.h>
|
||||||
|
#else
|
||||||
#include <emmintrin.h>
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KSW_SSE2_ONLY
|
#ifdef KSW_SSE2_ONLY
|
||||||
#undef __SSE4_1__
|
#undef __SSE4_1__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse4.1.h>
|
||||||
|
#else
|
||||||
#include <smmintrin.h>
|
#include <smmintrin.h>
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef KSW_CPU_DISPATCH
|
#ifdef KSW_CPU_DISPATCH
|
||||||
#ifdef __SSE4_1__
|
#ifdef __SSE4_1__
|
||||||
|
|||||||
+6
-1
@@ -1,9 +1,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <emmintrin.h>
|
|
||||||
#include "ksw2.h"
|
#include "ksw2.h"
|
||||||
|
|
||||||
|
#ifdef USE_SIMDE
|
||||||
|
#include <simde/x86/sse2.h>
|
||||||
|
#else
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#define LIKELY(x) __builtin_expect((x),1)
|
#define LIKELY(x) __builtin_expect((x),1)
|
||||||
#define UNLIKELY(x) __builtin_expect((x),0)
|
#define UNLIKELY(x) __builtin_expect((x),0)
|
||||||
|
|||||||
@@ -0,0 +1,344 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "mmpriv.h"
|
||||||
|
#include "kalloc.h"
|
||||||
|
#include "krmq.h"
|
||||||
|
|
||||||
|
uint64_t *mg_chain_backtrack(void *km, int64_t n, const int32_t *f, const int64_t *p, int32_t *v, int32_t *t, int32_t min_cnt, int32_t min_sc, int32_t *n_u_, int32_t *n_v_)
|
||||||
|
{
|
||||||
|
mm128_t *z;
|
||||||
|
uint64_t *u;
|
||||||
|
int64_t i, k, n_z, n_v;
|
||||||
|
int32_t n_u;
|
||||||
|
|
||||||
|
*n_u_ = *n_v_ = 0;
|
||||||
|
for (i = 0, n_z = 0; i < n; ++i) // precompute n_z
|
||||||
|
if (f[i] >= min_sc) ++n_z;
|
||||||
|
if (n_z == 0) return 0;
|
||||||
|
KMALLOC(km, z, n_z);
|
||||||
|
for (i = 0, k = 0; i < n; ++i) // populate z[]
|
||||||
|
if (f[i] >= min_sc) z[k].x = f[i], z[k++].y = i;
|
||||||
|
radix_sort_128x(z, z + n_z);
|
||||||
|
|
||||||
|
memset(t, 0, n * 4);
|
||||||
|
for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // precompute n_u
|
||||||
|
int64_t n_v0 = n_v;
|
||||||
|
int32_t sc;
|
||||||
|
for (i = z[k].y; i >= 0 && t[i] == 0; i = p[i])
|
||||||
|
++n_v, t[i] = 1;
|
||||||
|
sc = i < 0? z[k].x : (int32_t)z[k].x - f[i];
|
||||||
|
if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt)
|
||||||
|
++n_u;
|
||||||
|
else n_v = n_v0;
|
||||||
|
}
|
||||||
|
KMALLOC(km, u, n_u);
|
||||||
|
memset(t, 0, n * 4);
|
||||||
|
for (k = n_z - 1, n_v = n_u = 0; k >= 0; --k) { // populate u[]
|
||||||
|
int64_t n_v0 = n_v;
|
||||||
|
int32_t sc;
|
||||||
|
for (i = z[k].y; i >= 0 && t[i] == 0; i = p[i])
|
||||||
|
v[n_v++] = i, t[i] = 1;
|
||||||
|
sc = i < 0? z[k].x : (int32_t)z[k].x - f[i];
|
||||||
|
if (sc >= min_sc && n_v > n_v0 && n_v - n_v0 >= min_cnt)
|
||||||
|
u[n_u++] = (uint64_t)sc << 32 | (n_v - n_v0);
|
||||||
|
else n_v = n_v0;
|
||||||
|
}
|
||||||
|
kfree(km, z);
|
||||||
|
assert(n_v < INT32_MAX);
|
||||||
|
*n_u_ = n_u, *n_v_ = n_v;
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mm128_t *compact_a(void *km, int32_t n_u, uint64_t *u, int32_t n_v, int32_t *v, mm128_t *a)
|
||||||
|
{
|
||||||
|
mm128_t *b, *w;
|
||||||
|
uint64_t *u2;
|
||||||
|
int64_t i, j, k;
|
||||||
|
|
||||||
|
// write the result to b[]
|
||||||
|
KMALLOC(km, b, n_v);
|
||||||
|
for (i = 0, k = 0; i < n_u; ++i) {
|
||||||
|
int32_t k0 = k, ni = (int32_t)u[i];
|
||||||
|
for (j = 0; j < ni; ++j)
|
||||||
|
b[k++] = a[v[k0 + (ni - j - 1)]];
|
||||||
|
}
|
||||||
|
kfree(km, v);
|
||||||
|
|
||||||
|
// sort u[] and a[] by the target position, such that adjacent chains may be joined
|
||||||
|
KMALLOC(km, w, n_u);
|
||||||
|
for (i = k = 0; i < n_u; ++i) {
|
||||||
|
w[i].x = b[k].x, w[i].y = (uint64_t)k<<32|i;
|
||||||
|
k += (int32_t)u[i];
|
||||||
|
}
|
||||||
|
radix_sort_128x(w, w + n_u);
|
||||||
|
KMALLOC(km, u2, n_u);
|
||||||
|
for (i = k = 0; i < n_u; ++i) {
|
||||||
|
int32_t j = (int32_t)w[i].y, n = (int32_t)u[j];
|
||||||
|
u2[i] = u[j];
|
||||||
|
memcpy(&a[k], &b[w[i].y>>32], n * sizeof(mm128_t));
|
||||||
|
k += n;
|
||||||
|
}
|
||||||
|
memcpy(u, u2, n_u * 8);
|
||||||
|
memcpy(b, a, k * sizeof(mm128_t)); // write _a_ to _b_ and deallocate _a_ because _a_ is oversized, sometimes a lot
|
||||||
|
kfree(km, a); kfree(km, w); kfree(km, u2);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int32_t comput_sc(const mm128_t *ai, const mm128_t *aj, int32_t max_dist_x, int32_t max_dist_y, int32_t bw, float chn_pen_gap, float chn_pen_skip, int is_cdna, int n_seg)
|
||||||
|
{
|
||||||
|
int32_t dq = (int32_t)ai->y - (int32_t)aj->y, dr, dd, dg, q_span, sc;
|
||||||
|
int32_t sidi = (ai->y & MM_SEED_SEG_MASK) >> MM_SEED_SEG_SHIFT;
|
||||||
|
int32_t sidj = (aj->y & MM_SEED_SEG_MASK) >> MM_SEED_SEG_SHIFT;
|
||||||
|
if (dq <= 0 || dq > max_dist_x) return INT32_MIN;
|
||||||
|
dr = (int32_t)(ai->x - aj->x);
|
||||||
|
if (sidi == sidj && (dr == 0 || dq > max_dist_y)) return INT32_MIN;
|
||||||
|
dd = dr > dq? dr - dq : dq - dr;
|
||||||
|
if (sidi == sidj && dd > bw) return INT32_MIN;
|
||||||
|
if (n_seg > 1 && !is_cdna && sidi == sidj && dr > max_dist_y) return INT32_MIN;
|
||||||
|
dg = dr < dq? dr : dq;
|
||||||
|
q_span = aj->y>>32&0xff;
|
||||||
|
sc = q_span < dg? q_span : dg;
|
||||||
|
if (dd || dg > q_span) {
|
||||||
|
float lin_pen, log_pen;
|
||||||
|
lin_pen = chn_pen_gap * (float)dd + chn_pen_skip * (float)dg;
|
||||||
|
log_pen = dd >= 1? mg_log2(dd + 1) : 0.0f; // mg_log2() only works for dd>=2
|
||||||
|
if (is_cdna || sidi != sidj) {
|
||||||
|
if (sidi != sidj && dr == 0) ++sc; // possibly due to overlapping paired ends; give a minor bonus
|
||||||
|
else if (dr > dq || sidi != sidj) sc -= (int)(lin_pen < log_pen? lin_pen : log_pen); // deletion or jump between paired ends
|
||||||
|
else sc -= (int)(lin_pen + .5f * log_pen);
|
||||||
|
} else sc -= (int)(lin_pen + .5f * log_pen);
|
||||||
|
}
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input:
|
||||||
|
* a[].x: tid<<33 | rev<<32 | tpos
|
||||||
|
* a[].y: flags<<40 | q_span<<32 | q_pos
|
||||||
|
* Output:
|
||||||
|
* n_u: #chains
|
||||||
|
* u[]: score<<32 | #anchors (sum of lower 32 bits of u[] is the returned length of a[])
|
||||||
|
* input a[] is deallocated on return
|
||||||
|
*/
|
||||||
|
mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int max_iter, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
|
||||||
|
int is_cdna, int n_seg, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km)
|
||||||
|
{ // TODO: make sure this works when n has more than 32 bits
|
||||||
|
int32_t *f, *t, *v, n_u, n_v, mmax_f = 0;
|
||||||
|
int64_t *p, i, j, max_ii, st = 0, n_iter = 0;
|
||||||
|
uint64_t *u;
|
||||||
|
|
||||||
|
if (_u) *_u = 0, *n_u_ = 0;
|
||||||
|
if (n == 0 || a == 0) {
|
||||||
|
kfree(km, a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (max_dist_x < bw) max_dist_x = bw;
|
||||||
|
if (max_dist_y < bw && !is_cdna) max_dist_y = bw;
|
||||||
|
KMALLOC(km, p, n);
|
||||||
|
KMALLOC(km, f, n);
|
||||||
|
KMALLOC(km, v, n);
|
||||||
|
KCALLOC(km, t, n);
|
||||||
|
|
||||||
|
// fill the score and backtrack arrays
|
||||||
|
for (i = 0, max_ii = -1; i < n; ++i) {
|
||||||
|
int64_t max_j = -1, end_j;
|
||||||
|
int32_t max_f = a[i].y>>32&0xff, n_skip = 0;
|
||||||
|
while (st < i && (a[i].x>>32 != a[st].x>>32 || a[i].x > a[st].x + max_dist_x)) ++st;
|
||||||
|
if (i - st > max_iter) st = i - max_iter;
|
||||||
|
for (j = i - 1; j >= st; --j) {
|
||||||
|
int32_t sc;
|
||||||
|
sc = comput_sc(&a[i], &a[j], max_dist_x, max_dist_y, bw, chn_pen_gap, chn_pen_skip, is_cdna, n_seg);
|
||||||
|
++n_iter;
|
||||||
|
if (sc == INT32_MIN) continue;
|
||||||
|
sc += f[j];
|
||||||
|
if (sc > max_f) {
|
||||||
|
max_f = sc, max_j = j;
|
||||||
|
if (n_skip > 0) --n_skip;
|
||||||
|
} else if (t[j] == (int32_t)i) {
|
||||||
|
if (++n_skip > max_skip)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p[j] >= 0) t[p[j]] = i;
|
||||||
|
}
|
||||||
|
end_j = j;
|
||||||
|
if (max_ii < 0 || a[i].x - a[max_ii].x > (int64_t)max_dist_x) {
|
||||||
|
int32_t max = INT32_MIN;
|
||||||
|
max_ii = -1;
|
||||||
|
for (j = i - 1; j >= st; --j)
|
||||||
|
if (max < f[j]) max = f[j], max_ii = j;
|
||||||
|
}
|
||||||
|
if (max_ii >= 0 && max_ii < end_j) {
|
||||||
|
int32_t tmp;
|
||||||
|
tmp = comput_sc(&a[i], &a[max_ii], max_dist_x, max_dist_y, bw, chn_pen_gap, chn_pen_skip, is_cdna, n_seg);
|
||||||
|
if (tmp != INT32_MIN && max_f < tmp + f[max_ii])
|
||||||
|
max_f = tmp + f[max_ii], max_j = max_ii;
|
||||||
|
}
|
||||||
|
f[i] = max_f, p[i] = max_j;
|
||||||
|
v[i] = max_j >= 0 && v[max_j] > max_f? v[max_j] : max_f; // v[] keeps the peak score up to i; f[] is the score ending at i, not always the peak
|
||||||
|
if (max_ii < 0 || (a[i].x - a[max_ii].x <= (int64_t)max_dist_x && f[max_ii] < f[i]))
|
||||||
|
max_ii = i;
|
||||||
|
if (mmax_f < max_f) mmax_f = max_f;
|
||||||
|
}
|
||||||
|
|
||||||
|
u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, &n_u, &n_v);
|
||||||
|
*n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here
|
||||||
|
kfree(km, p); kfree(km, f); kfree(km, t);
|
||||||
|
if (n_u == 0) {
|
||||||
|
kfree(km, a); kfree(km, v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return compact_a(km, n_u, u, n_v, v, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct lc_elem_s {
|
||||||
|
int32_t y;
|
||||||
|
int64_t i;
|
||||||
|
double pri;
|
||||||
|
KRMQ_HEAD(struct lc_elem_s) head;
|
||||||
|
} lc_elem_t;
|
||||||
|
|
||||||
|
#define lc_elem_cmp(a, b) ((a)->y < (b)->y? -1 : (a)->y > (b)->y? 1 : ((a)->i > (b)->i) - ((a)->i < (b)->i))
|
||||||
|
#define lc_elem_lt2(a, b) ((a)->pri < (b)->pri)
|
||||||
|
KRMQ_INIT(lc_elem, lc_elem_t, head, lc_elem_cmp, lc_elem_lt2)
|
||||||
|
|
||||||
|
KALLOC_POOL_INIT(rmq, lc_elem_t)
|
||||||
|
|
||||||
|
static inline int32_t comput_sc_simple(const mm128_t *ai, const mm128_t *aj, float chn_pen_gap, float chn_pen_skip, int32_t *exact, int32_t *width)
|
||||||
|
{
|
||||||
|
int32_t dq = (int32_t)ai->y - (int32_t)aj->y, dr, dd, dg, q_span, sc;
|
||||||
|
dr = (int32_t)(ai->x - aj->x);
|
||||||
|
*width = dd = dr > dq? dr - dq : dq - dr;
|
||||||
|
dg = dr < dq? dr : dq;
|
||||||
|
q_span = aj->y>>32&0xff;
|
||||||
|
sc = q_span < dg? q_span : dg;
|
||||||
|
if (exact) *exact = (dd == 0 && dg <= q_span);
|
||||||
|
if (dd || dq > q_span) {
|
||||||
|
float lin_pen, log_pen;
|
||||||
|
lin_pen = chn_pen_gap * (float)dd + chn_pen_skip * (float)dg;
|
||||||
|
log_pen = dd >= 1? mg_log2(dd + 1) : 0.0f; // mg_log2() only works for dd>=2
|
||||||
|
sc -= (int)(lin_pen + .5f * log_pen);
|
||||||
|
}
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm128_t *mg_lchain_rmq(int max_dist, int max_dist_inner, int bw, int max_chn_skip, int cap_rmq_size, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
|
||||||
|
int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km)
|
||||||
|
{
|
||||||
|
int32_t *f,*t, *v, n_u, n_v, mmax_f = 0, max_rmq_size = 0;
|
||||||
|
int64_t *p, i, i0, st = 0, st_inner = 0, n_iter = 0;
|
||||||
|
uint64_t *u;
|
||||||
|
lc_elem_t *root = 0, *root_inner = 0;
|
||||||
|
void *mem_mp = 0;
|
||||||
|
kmp_rmq_t *mp;
|
||||||
|
|
||||||
|
if (_u) *_u = 0, *n_u_ = 0;
|
||||||
|
if (n == 0 || a == 0) {
|
||||||
|
kfree(km, a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (max_dist < bw) max_dist = bw;
|
||||||
|
if (max_dist_inner <= 0 || max_dist_inner >= max_dist) max_dist_inner = 0;
|
||||||
|
KMALLOC(km, p, n);
|
||||||
|
KMALLOC(km, f, n);
|
||||||
|
KCALLOC(km, t, n);
|
||||||
|
KMALLOC(km, v, n);
|
||||||
|
mem_mp = km_init2(km, 0x10000);
|
||||||
|
mp = kmp_init_rmq(mem_mp);
|
||||||
|
|
||||||
|
// fill the score and backtrack arrays
|
||||||
|
for (i = i0 = 0; i < n; ++i) {
|
||||||
|
int64_t max_j = -1;
|
||||||
|
int32_t q_span = a[i].y>>32&0xff, max_f = q_span;
|
||||||
|
lc_elem_t s, *q, *r, lo, hi;
|
||||||
|
// add in-range anchors
|
||||||
|
if (i0 < i && a[i0].x != a[i].x) {
|
||||||
|
int64_t j;
|
||||||
|
for (j = i0; j < i; ++j) {
|
||||||
|
q = kmp_alloc_rmq(mp);
|
||||||
|
q->y = (int32_t)a[j].y, q->i = j, q->pri = -(f[j] + 0.5 * chn_pen_gap * ((int32_t)a[j].x + (int32_t)a[j].y));
|
||||||
|
krmq_insert(lc_elem, &root, q, 0);
|
||||||
|
if (max_dist_inner > 0) {
|
||||||
|
r = kmp_alloc_rmq(mp);
|
||||||
|
*r = *q;
|
||||||
|
krmq_insert(lc_elem, &root_inner, r, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i0 = i;
|
||||||
|
}
|
||||||
|
// get rid of active chains out of range
|
||||||
|
while (st < i && (a[i].x>>32 != a[st].x>>32 || a[i].x > a[st].x + max_dist || krmq_size(head, root) > cap_rmq_size)) {
|
||||||
|
s.y = (int32_t)a[st].y, s.i = st;
|
||||||
|
if ((q = krmq_find(lc_elem, root, &s, 0)) != 0) {
|
||||||
|
q = krmq_erase(lc_elem, &root, q, 0);
|
||||||
|
kmp_free_rmq(mp, q);
|
||||||
|
}
|
||||||
|
++st;
|
||||||
|
}
|
||||||
|
if (max_dist_inner > 0) { // similar to the block above, but applied to the inner tree
|
||||||
|
while (st_inner < i && (a[i].x>>32 != a[st_inner].x>>32 || a[i].x > a[st_inner].x + max_dist_inner || krmq_size(head, root_inner) > cap_rmq_size)) {
|
||||||
|
s.y = (int32_t)a[st_inner].y, s.i = st_inner;
|
||||||
|
if ((q = krmq_find(lc_elem, root_inner, &s, 0)) != 0) {
|
||||||
|
q = krmq_erase(lc_elem, &root_inner, q, 0);
|
||||||
|
kmp_free_rmq(mp, q);
|
||||||
|
}
|
||||||
|
++st_inner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// RMQ
|
||||||
|
lo.i = INT32_MAX, lo.y = (int32_t)a[i].y - max_dist;
|
||||||
|
hi.i = 0, hi.y = (int32_t)a[i].y;
|
||||||
|
if ((q = krmq_rmq(lc_elem, root, &lo, &hi)) != 0) {
|
||||||
|
int32_t sc, exact, width, n_skip = 0;
|
||||||
|
int64_t j = q->i;
|
||||||
|
assert(q->y >= lo.y && q->y <= hi.y);
|
||||||
|
sc = f[j] + comput_sc_simple(&a[i], &a[j], chn_pen_gap, chn_pen_skip, &exact, &width);
|
||||||
|
if (width <= bw && sc > max_f) max_f = sc, max_j = j;
|
||||||
|
if (!exact && root_inner && (int32_t)a[i].y > 0) {
|
||||||
|
lc_elem_t *lo, *hi;
|
||||||
|
s.y = (int32_t)a[i].y - 1, s.i = n;
|
||||||
|
krmq_interval(lc_elem, root_inner, &s, &lo, &hi);
|
||||||
|
if (lo) {
|
||||||
|
const lc_elem_t *q;
|
||||||
|
int32_t width, n_rmq_iter = 0;
|
||||||
|
krmq_itr_t(lc_elem) itr;
|
||||||
|
krmq_itr_find(lc_elem, root_inner, lo, &itr);
|
||||||
|
while ((q = krmq_at(&itr)) != 0) {
|
||||||
|
if (q->y < (int32_t)a[i].y - max_dist_inner) break;
|
||||||
|
++n_rmq_iter;
|
||||||
|
j = q->i;
|
||||||
|
sc = f[j] + comput_sc_simple(&a[i], &a[j], chn_pen_gap, chn_pen_skip, 0, &width);
|
||||||
|
if (width <= bw) {
|
||||||
|
if (sc > max_f) {
|
||||||
|
max_f = sc, max_j = j;
|
||||||
|
if (n_skip > 0) --n_skip;
|
||||||
|
} else if (t[j] == (int32_t)i) {
|
||||||
|
if (++n_skip > max_chn_skip)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p[j] >= 0) t[p[j]] = i;
|
||||||
|
}
|
||||||
|
if (!krmq_itr_prev(lc_elem, &itr)) break;
|
||||||
|
}
|
||||||
|
n_iter += n_rmq_iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// set max
|
||||||
|
assert(max_j < 0 || (a[max_j].x < a[i].x && (int32_t)a[max_j].y < (int32_t)a[i].y));
|
||||||
|
f[i] = max_f, p[i] = max_j;
|
||||||
|
v[i] = max_j >= 0 && v[max_j] > max_f? v[max_j] : max_f; // v[] keeps the peak score up to i; f[] is the score ending at i, not always the peak
|
||||||
|
if (mmax_f < max_f) mmax_f = max_f;
|
||||||
|
if (max_rmq_size < krmq_size(head, root)) max_rmq_size = krmq_size(head, root);
|
||||||
|
}
|
||||||
|
km_destroy(mem_mp);
|
||||||
|
|
||||||
|
u = mg_chain_backtrack(km, n, f, p, v, t, min_cnt, min_sc, &n_u, &n_v);
|
||||||
|
*n_u_ = n_u, *_u = u; // NB: note that u[] may not be sorted by score here
|
||||||
|
kfree(km, p); kfree(km, f); kfree(km, t);
|
||||||
|
if (n_u == 0) {
|
||||||
|
kfree(km, a); kfree(km, v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return compact_a(km, n_u, u, n_v, v, a);
|
||||||
|
}
|
||||||
Submodule
+1
Submodule lib/simde added at b30129b3b4
@@ -1,12 +1,13 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "bseq.h"
|
#include "bseq.h"
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
#include "ketopt.h"
|
#include "ketopt.h"
|
||||||
|
|
||||||
#define MM_VERSION "2.13-r852-dirty"
|
#define MM_VERSION "2.22-r1101"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
@@ -60,7 +61,19 @@ static ko_longopt_t long_options[] = {
|
|||||||
{ "split-prefix", ko_required_argument, 334 },
|
{ "split-prefix", ko_required_argument, 334 },
|
||||||
{ "no-end-flt", ko_no_argument, 335 },
|
{ "no-end-flt", ko_no_argument, 335 },
|
||||||
{ "hard-mask-level",ko_no_argument, 336 },
|
{ "hard-mask-level",ko_no_argument, 336 },
|
||||||
{ "bed", ko_required_argument, 337 },
|
{ "cap-sw-mem", ko_required_argument, 337 },
|
||||||
|
{ "max-qlen", ko_required_argument, 338 },
|
||||||
|
{ "max-chain-iter", ko_required_argument, 339 },
|
||||||
|
{ "junc-bed", ko_required_argument, 340 },
|
||||||
|
{ "junc-bonus", ko_required_argument, 341 },
|
||||||
|
{ "sam-hit-only", ko_no_argument, 342 },
|
||||||
|
{ "chain-gap-scale",ko_required_argument, 343 },
|
||||||
|
{ "alt", ko_required_argument, 344 },
|
||||||
|
{ "alt-drop", ko_required_argument, 345 },
|
||||||
|
{ "mask-len", ko_required_argument, 346 },
|
||||||
|
{ "rmq", ko_optional_argument, 347 },
|
||||||
|
{ "qstrand", ko_no_argument, 348 },
|
||||||
|
{ "cap-kalloc", ko_required_argument, 349 },
|
||||||
{ "help", ko_no_argument, 'h' },
|
{ "help", ko_no_argument, 'h' },
|
||||||
{ "max-intron-len", ko_required_argument, 'G' },
|
{ "max-intron-len", ko_required_argument, 'G' },
|
||||||
{ "version", ko_no_argument, 'V' },
|
{ "version", ko_no_argument, 'V' },
|
||||||
@@ -72,18 +85,24 @@ static ko_longopt_t long_options[] = {
|
|||||||
{ 0, 0, 0 }
|
{ 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int64_t mm_parse_num(const char *str)
|
static inline int64_t mm_parse_num2(const char *str, char **q)
|
||||||
{
|
{
|
||||||
double x;
|
double x;
|
||||||
char *p;
|
char *p;
|
||||||
x = strtod(str, &p);
|
x = strtod(str, &p);
|
||||||
if (*p == 'G' || *p == 'g') x *= 1e9;
|
if (*p == 'G' || *p == 'g') x *= 1e9, ++p;
|
||||||
else if (*p == 'M' || *p == 'm') x *= 1e6;
|
else if (*p == 'M' || *p == 'm') x *= 1e6, ++p;
|
||||||
else if (*p == 'K' || *p == 'k') x *= 1e3;
|
else if (*p == 'K' || *p == 'k') x *= 1e3, ++p;
|
||||||
|
if (q) *q = p;
|
||||||
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)
|
static inline int64_t mm_parse_num(const char *str)
|
||||||
|
{
|
||||||
|
return mm_parse_num2(str, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void yes_or_no(mm_mapopt_t *opt, int64_t flag, int long_idx, const char *arg, int yes_to_set)
|
||||||
{
|
{
|
||||||
if (yes_to_set) {
|
if (yes_to_set) {
|
||||||
if (strcmp(arg, "yes") == 0 || strcmp(arg, "y") == 0) opt->flag |= flag;
|
if (strcmp(arg, "yes") == 0 || strcmp(arg, "y") == 0) opt->flag |= flag;
|
||||||
@@ -98,12 +117,12 @@ static inline void yes_or_no(mm_mapopt_t *opt, int flag, int long_idx, const cha
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
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:yYP";
|
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:yYPo:e:U:";
|
||||||
ketopt_t o = KETOPT_INIT;
|
ketopt_t o = KETOPT_INIT;
|
||||||
mm_mapopt_t opt;
|
mm_mapopt_t opt;
|
||||||
mm_idxopt_t ipt;
|
mm_idxopt_t ipt;
|
||||||
int i, c, n_threads = 3, n_parts, old_best_n = -1;
|
int i, c, n_threads = 3, n_parts, old_best_n = -1;
|
||||||
char *fnw = 0, *fn_bed = 0, *rg = 0, *s;
|
char *fnw = 0, *rg = 0, *junc_bed = 0, *s, *alt_list = 0;
|
||||||
FILE *fp_help = stderr;
|
FILE *fp_help = stderr;
|
||||||
mm_idx_reader_t *idx_rdr;
|
mm_idx_reader_t *idx_rdr;
|
||||||
mm_idx_t *mi;
|
mm_idx_t *mi;
|
||||||
@@ -123,7 +142,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(stderr, "[ERROR] missing option argument\n");
|
fprintf(stderr, "[ERROR] missing option argument\n");
|
||||||
return 1;
|
return 1;
|
||||||
} else if (c == '?') {
|
} else if (c == '?') {
|
||||||
fprintf(stderr, "[ERROR] unknown option in \"%s\"\n", argv[o.i]);
|
fprintf(stderr, "[ERROR] unknown option in \"%s\"\n", argv[o.i - 1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +153,6 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 'k') ipt.k = atoi(o.arg);
|
else if (c == 'k') ipt.k = atoi(o.arg);
|
||||||
else if (c == 'H') ipt.flag |= MM_I_HPC;
|
else if (c == 'H') ipt.flag |= MM_I_HPC;
|
||||||
else if (c == 'd') fnw = o.arg; // the above are indexing related options, except -I
|
else if (c == 'd') fnw = o.arg; // the above are indexing related options, except -I
|
||||||
else if (c == 'r') opt.bw = (int)mm_parse_num(o.arg);
|
|
||||||
else if (c == 't') n_threads = atoi(o.arg);
|
else if (c == 't') n_threads = atoi(o.arg);
|
||||||
else if (c == 'v') mm_verbose = atoi(o.arg);
|
else if (c == 'v') mm_verbose = atoi(o.arg);
|
||||||
else if (c == 'g') opt.max_gap = (int)mm_parse_num(o.arg);
|
else if (c == 'g') opt.max_gap = (int)mm_parse_num(o.arg);
|
||||||
@@ -160,16 +178,26 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 's') opt.min_dp_max = atoi(o.arg);
|
else if (c == 's') opt.min_dp_max = atoi(o.arg);
|
||||||
else if (c == 'C') opt.noncan = atoi(o.arg);
|
else if (c == 'C') opt.noncan = atoi(o.arg);
|
||||||
else if (c == 'I') ipt.batch_size = mm_parse_num(o.arg);
|
else if (c == 'I') ipt.batch_size = mm_parse_num(o.arg);
|
||||||
else if (c == 'K') opt.mini_batch_size = (int)mm_parse_num(o.arg);
|
else if (c == 'K') opt.mini_batch_size = mm_parse_num(o.arg);
|
||||||
|
else if (c == 'e') opt.occ_dist = mm_parse_num(o.arg);
|
||||||
else if (c == 'R') rg = o.arg;
|
else if (c == 'R') rg = o.arg;
|
||||||
else if (c == 'h') fp_help = stdout;
|
else if (c == 'h') fp_help = stdout;
|
||||||
else if (c == '2') opt.flag |= MM_F_2_IO_THREADS;
|
else if (c == '2') opt.flag |= MM_F_2_IO_THREADS;
|
||||||
|
else if (c == 'o') {
|
||||||
|
if (strcmp(o.arg, "-") != 0) {
|
||||||
|
if (freopen(o.arg, "wb", stdout) == NULL) {
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m failed to write the output to file '%s'\033[0m: %s\n", o.arg, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (c == 300) ipt.bucket_bits = atoi(o.arg); // --bucket-bits
|
else if (c == 300) ipt.bucket_bits = atoi(o.arg); // --bucket-bits
|
||||||
else if (c == 302) opt.seed = atoi(o.arg); // --seed
|
else if (c == 302) opt.seed = atoi(o.arg); // --seed
|
||||||
else if (c == 303) mm_dbg_flag |= MM_DBG_NO_KALLOC; // --no-kalloc
|
else if (c == 303) mm_dbg_flag |= MM_DBG_NO_KALLOC; // --no-kalloc
|
||||||
else if (c == 304) mm_dbg_flag |= MM_DBG_PRINT_QNAME; // --print-qname
|
else if (c == 304) mm_dbg_flag |= MM_DBG_PRINT_QNAME; // --print-qname
|
||||||
else if (c == 306) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_SEED, n_threads = 1; // --print-seed
|
else if (c == 306) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_SEED, n_threads = 1; // --print-seed
|
||||||
else if (c == 307) opt.max_chain_skip = atoi(o.arg); // --max-chain-skip
|
else if (c == 307) opt.max_chain_skip = atoi(o.arg); // --max-chain-skip
|
||||||
|
else if (c == 339) opt.max_chain_iter = atoi(o.arg); // --max-chain-iter
|
||||||
else if (c == 308) opt.min_ksw_len = atoi(o.arg); // --min-dp-len
|
else if (c == 308) opt.min_ksw_len = atoi(o.arg); // --min-dp-len
|
||||||
else if (c == 309) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_ALN_SEQ, n_threads = 1; // --print-aln-seq
|
else if (c == 309) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_ALN_SEQ, n_threads = 1; // --print-aln-seq
|
||||||
else if (c == 310) opt.flag |= MM_F_SPLICE; // --splice
|
else if (c == 310) opt.flag |= MM_F_SPLICE; // --splice
|
||||||
@@ -184,15 +212,26 @@ int main(int argc, char *argv[])
|
|||||||
else if (c == 327) opt.max_clip_ratio = atof(o.arg); // --max-clip-ratio
|
else if (c == 327) opt.max_clip_ratio = atof(o.arg); // --max-clip-ratio
|
||||||
else if (c == 328) opt.min_mid_occ = atoi(o.arg); // --min-occ-floor
|
else if (c == 328) opt.min_mid_occ = atoi(o.arg); // --min-occ-floor
|
||||||
else if (c == 329) opt.flag |= MM_F_OUT_MD; // --MD
|
else if (c == 329) opt.flag |= MM_F_OUT_MD; // --MD
|
||||||
else if (c == 330) opt.min_join_flank_ratio = atof(o.arg); // --lj-min-ratio
|
|
||||||
else if (c == 331) opt.sc_ambi = atoi(o.arg); // --score-N
|
else if (c == 331) opt.sc_ambi = atoi(o.arg); // --score-N
|
||||||
else if (c == 332) opt.flag |= MM_F_EQX; // --eqx
|
else if (c == 332) opt.flag |= MM_F_EQX; // --eqx
|
||||||
else if (c == 333) opt.flag |= MM_F_PAF_NO_HIT; // --paf-no-hit
|
else if (c == 333) opt.flag |= MM_F_PAF_NO_HIT; // --paf-no-hit
|
||||||
else if (c == 334) opt.split_prefix = o.arg; // --split-prefix
|
else if (c == 334) opt.split_prefix = o.arg; // --split-prefix
|
||||||
else if (c == 335) opt.flag |= MM_F_NO_END_FLT; // --no-end-flt
|
else if (c == 335) opt.flag |= MM_F_NO_END_FLT; // --no-end-flt
|
||||||
else if (c == 336) opt.flag |= MM_F_HARD_MLEVEL; // --hard-mask-level
|
else if (c == 336) opt.flag |= MM_F_HARD_MLEVEL; // --hard-mask-level
|
||||||
else if (c == 337) fn_bed = o.arg; // --bed-prefer
|
else if (c == 337) opt.max_sw_mat = mm_parse_num(o.arg); // --cap-sw-mat
|
||||||
else if (c == 314) { // --frag
|
else if (c == 338) opt.max_qlen = mm_parse_num(o.arg); // --max-qlen
|
||||||
|
else if (c == 340) junc_bed = o.arg; // --junc-bed
|
||||||
|
else if (c == 341) opt.junc_bonus = atoi(o.arg); // --junc-bonus
|
||||||
|
else if (c == 342) opt.flag |= MM_F_SAM_HIT_ONLY; // --sam-hit-only
|
||||||
|
else if (c == 343) opt.chain_gap_scale = atof(o.arg); // --chain-gap-scale
|
||||||
|
else if (c == 344) alt_list = o.arg; // --alt
|
||||||
|
else if (c == 345) opt.alt_drop = atof(o.arg); // --alt-drop
|
||||||
|
else if (c == 346) opt.mask_len = mm_parse_num(o.arg); // --mask-len
|
||||||
|
else if (c == 348) opt.flag |= MM_F_QSTRAND | MM_F_NO_INV; // --qstrand
|
||||||
|
else if (c == 349) opt.cap_kalloc = mm_parse_num(o.arg); // --cap-kalloc
|
||||||
|
else if (c == 330) {
|
||||||
|
fprintf(stderr, "[WARNING] \033[1;31m --lj-min-ratio has been deprecated.\033[0m\n");
|
||||||
|
} else if (c == 314) { // --frag
|
||||||
yes_or_no(&opt, MM_F_FRAG_MODE, o.longidx, o.arg, 1);
|
yes_or_no(&opt, MM_F_FRAG_MODE, o.longidx, o.arg, 1);
|
||||||
} else if (c == 315) { // --secondary
|
} else if (c == 315) { // --secondary
|
||||||
yes_or_no(&opt, MM_F_NO_PRINT_2ND, o.longidx, o.arg, 0);
|
yes_or_no(&opt, MM_F_NO_PRINT_2ND, o.longidx, o.arg, 0);
|
||||||
@@ -213,6 +252,8 @@ int main(int argc, char *argv[])
|
|||||||
yes_or_no(&opt, MM_F_HEAP_SORT, o.longidx, o.arg, 1);
|
yes_or_no(&opt, MM_F_HEAP_SORT, o.longidx, o.arg, 1);
|
||||||
} else if (c == 326) { // --dual
|
} else if (c == 326) { // --dual
|
||||||
yes_or_no(&opt, MM_F_NO_DUAL, o.longidx, o.arg, 0);
|
yes_or_no(&opt, MM_F_NO_DUAL, o.longidx, o.arg, 0);
|
||||||
|
} else if (c == 347) { // --rmq
|
||||||
|
yes_or_no(&opt, MM_F_RMQ, o.longidx, o.arg, 1);
|
||||||
} 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)
|
||||||
@@ -220,6 +261,12 @@ int main(int argc, char *argv[])
|
|||||||
} else if (c == 'V') {
|
} else if (c == 'V') {
|
||||||
puts(MM_VERSION);
|
puts(MM_VERSION);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (c == 'r') {
|
||||||
|
opt.bw = (int)mm_parse_num2(o.arg, &s);
|
||||||
|
if (*s == ',') opt.bw_long = (int)mm_parse_num2(s + 1, &s);
|
||||||
|
} else if (c == 'U') {
|
||||||
|
opt.min_mid_occ = strtol(o.arg, &s, 10);
|
||||||
|
if (*s == ',') opt.max_mid_occ = strtol(s + 1, &s, 10);
|
||||||
} else if (c == 'f') {
|
} else if (c == 'f') {
|
||||||
double x;
|
double x;
|
||||||
char *p;
|
char *p;
|
||||||
@@ -266,7 +313,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " Indexing:\n");
|
fprintf(fp_help, " Indexing:\n");
|
||||||
fprintf(fp_help, " -H use homopolymer-compressed k-mer (preferrable for PacBio)\n");
|
fprintf(fp_help, " -H use homopolymer-compressed k-mer (preferrable for PacBio)\n");
|
||||||
fprintf(fp_help, " -k INT k-mer size (no larger than 28) [%d]\n", ipt.k);
|
fprintf(fp_help, " -k INT k-mer size (no larger than 28) [%d]\n", ipt.k);
|
||||||
fprintf(fp_help, " -w INT minizer window size [%d]\n", ipt.w);
|
fprintf(fp_help, " -w INT minimizer window size [%d]\n", ipt.w);
|
||||||
fprintf(fp_help, " -I NUM split index for every ~NUM input bases [4G]\n");
|
fprintf(fp_help, " -I NUM split index for every ~NUM input bases [4G]\n");
|
||||||
fprintf(fp_help, " -d FILE dump index to FILE []\n");
|
fprintf(fp_help, " -d FILE dump index to FILE []\n");
|
||||||
fprintf(fp_help, " Mapping:\n");
|
fprintf(fp_help, " Mapping:\n");
|
||||||
@@ -274,7 +321,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " -g NUM stop chain enlongation if there are no minimizers in INT-bp [%d]\n", opt.max_gap);
|
fprintf(fp_help, " -g NUM stop chain enlongation if there are no minimizers in INT-bp [%d]\n", opt.max_gap);
|
||||||
fprintf(fp_help, " -G NUM max intron length (effective with -xsplice; changing -r) [200k]\n");
|
fprintf(fp_help, " -G NUM max intron length (effective with -xsplice; changing -r) [200k]\n");
|
||||||
fprintf(fp_help, " -F NUM max fragment length (effective with -xsr or in the fragment mode) [800]\n");
|
fprintf(fp_help, " -F NUM max fragment length (effective with -xsr or in the fragment mode) [800]\n");
|
||||||
fprintf(fp_help, " -r NUM bandwidth used in chaining and DP-based alignment [%d]\n", opt.bw);
|
fprintf(fp_help, " -r NUM[,NUM] chaining/alignment bandwidth and long-join bandwidth [%d,%d]\n", opt.bw, opt.bw_long);
|
||||||
fprintf(fp_help, " -n INT minimal number of minimizers on a chain [%d]\n", opt.min_cnt);
|
fprintf(fp_help, " -n INT minimal number of minimizers on a chain [%d]\n", opt.min_cnt);
|
||||||
fprintf(fp_help, " -m INT minimal chaining score (matching bases minus log gap penalty) [%d]\n", opt.min_chain_score);
|
fprintf(fp_help, " -m INT minimal chaining score (matching bases minus log gap penalty) [%d]\n", opt.min_chain_score);
|
||||||
// fprintf(fp_help, " -T INT SDUST threshold; 0 to disable SDUST [%d]\n", opt.sdust_thres); // TODO: this option is never used; might be buggy
|
// fprintf(fp_help, " -T INT SDUST threshold; 0 to disable SDUST [%d]\n", opt.sdust_thres); // TODO: this option is never used; might be buggy
|
||||||
@@ -283,7 +330,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " -N INT retain at most INT secondary alignments [%d]\n", opt.best_n);
|
fprintf(fp_help, " -N INT retain at most INT secondary alignments [%d]\n", opt.best_n);
|
||||||
fprintf(fp_help, " Alignment:\n");
|
fprintf(fp_help, " Alignment:\n");
|
||||||
fprintf(fp_help, " -A INT matching score [%d]\n", opt.a);
|
fprintf(fp_help, " -A INT matching score [%d]\n", opt.a);
|
||||||
fprintf(fp_help, " -B INT mismatch penalty [%d]\n", opt.b);
|
fprintf(fp_help, " -B INT mismatch penalty (larger value for lower divergence) [%d]\n", opt.b);
|
||||||
fprintf(fp_help, " -O INT[,INT] gap open penalty [%d,%d]\n", opt.q, opt.q2);
|
fprintf(fp_help, " -O INT[,INT] gap open penalty [%d,%d]\n", opt.q, opt.q2);
|
||||||
fprintf(fp_help, " -E INT[,INT] gap extension penalty; a k-long gap costs min{O1+k*E1,O2+k*E2} [%d,%d]\n", opt.e, opt.e2);
|
fprintf(fp_help, " -E INT[,INT] gap extension penalty; a k-long gap costs min{O1+k*E1,O2+k*E2} [%d,%d]\n", opt.e, opt.e2);
|
||||||
fprintf(fp_help, " -z INT[,INT] Z-drop score and inversion Z-drop score [%d,%d]\n", opt.zdrop, opt.zdrop_inv);
|
fprintf(fp_help, " -z INT[,INT] Z-drop score and inversion Z-drop score [%d,%d]\n", opt.zdrop, opt.zdrop_inv);
|
||||||
@@ -291,7 +338,7 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " -u CHAR how to find GT-AG. f:transcript strand, b:both strands, n:don't match GT-AG [n]\n");
|
fprintf(fp_help, " -u CHAR how to find GT-AG. f:transcript strand, b:both strands, n:don't match GT-AG [n]\n");
|
||||||
fprintf(fp_help, " Input/Output:\n");
|
fprintf(fp_help, " Input/Output:\n");
|
||||||
fprintf(fp_help, " -a output in the SAM format (PAF by default)\n");
|
fprintf(fp_help, " -a output in the SAM format (PAF by default)\n");
|
||||||
fprintf(fp_help, " -Q don't output base quality in SAM\n");
|
fprintf(fp_help, " -o FILE output alignments to FILE [stdout]\n");
|
||||||
fprintf(fp_help, " -L write CIGAR with >65535 ops at the CG tag\n");
|
fprintf(fp_help, " -L write CIGAR with >65535 ops at the CG tag\n");
|
||||||
fprintf(fp_help, " -R STR SAM read group line in a format like '@RG\\tID:foo\\tSM:bar' []\n");
|
fprintf(fp_help, " -R STR SAM read group line in a format like '@RG\\tID:foo\\tSM:bar' []\n");
|
||||||
fprintf(fp_help, " -c output CIGAR in PAF\n");
|
fprintf(fp_help, " -c output CIGAR in PAF\n");
|
||||||
@@ -305,11 +352,12 @@ int main(int argc, char *argv[])
|
|||||||
fprintf(fp_help, " --version show version number\n");
|
fprintf(fp_help, " --version show version number\n");
|
||||||
fprintf(fp_help, " Preset:\n");
|
fprintf(fp_help, " Preset:\n");
|
||||||
fprintf(fp_help, " -x STR preset (always applied before other options; see minimap2.1 for details) []\n");
|
fprintf(fp_help, " -x STR preset (always applied before other options; see minimap2.1 for details) []\n");
|
||||||
fprintf(fp_help, " - map-pb/map-ont: PacBio/Nanopore vs reference mapping\n");
|
fprintf(fp_help, " - map-pb/map-ont - PacBio CLR/Nanopore vs reference mapping\n");
|
||||||
fprintf(fp_help, " - ava-pb/ava-ont: PacBio/Nanopore read overlap\n");
|
fprintf(fp_help, " - map-hifi - PacBio HiFi reads vs reference mapping\n");
|
||||||
fprintf(fp_help, " - asm5/asm10/asm20: asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\n");
|
fprintf(fp_help, " - ava-pb/ava-ont - PacBio/Nanopore read overlap\n");
|
||||||
fprintf(fp_help, " - splice: long-read spliced alignment\n");
|
fprintf(fp_help, " - asm5/asm10/asm20 - asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\n");
|
||||||
fprintf(fp_help, " - sr: genomic short-read mapping\n");
|
fprintf(fp_help, " - splice/splice:hq - long-read/Pacbio-CCS spliced alignment\n");
|
||||||
|
fprintf(fp_help, " - sr - genomic short-read mapping\n");
|
||||||
fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of these and other advanced command-line options.\n");
|
fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of these and other advanced command-line options.\n");
|
||||||
return fp_help == stdout? 0 : 1;
|
return fp_help == stdout? 0 : 1;
|
||||||
}
|
}
|
||||||
@@ -320,7 +368,7 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
idx_rdr = mm_idx_reader_open(argv[o.ind], &ipt, fnw);
|
idx_rdr = mm_idx_reader_open(argv[o.ind], &ipt, fnw);
|
||||||
if (idx_rdr == 0) {
|
if (idx_rdr == 0) {
|
||||||
fprintf(stderr, "[ERROR] failed to open file '%s'\n", argv[o.ind]);
|
fprintf(stderr, "[ERROR] failed to open file '%s': %s\n", argv[o.ind], strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!idx_rdr->is_idx && fnw == 0 && argc - o.ind < 2) {
|
if (!idx_rdr->is_idx && fnw == 0 && argc - o.ind < 2) {
|
||||||
@@ -331,6 +379,7 @@ int main(int argc, char *argv[])
|
|||||||
if (opt.best_n == 0 && (opt.flag&MM_F_CIGAR) && mm_verbose >= 2)
|
if (opt.best_n == 0 && (opt.flag&MM_F_CIGAR) && mm_verbose >= 2)
|
||||||
fprintf(stderr, "[WARNING]\033[1;31m `-N 0' reduces alignment accuracy. Please use --secondary=no to suppress secondary alignments.\033[0m\n");
|
fprintf(stderr, "[WARNING]\033[1;31m `-N 0' reduces alignment accuracy. Please use --secondary=no to suppress secondary alignments.\033[0m\n");
|
||||||
while ((mi = mm_idx_reader_read(idx_rdr, n_threads)) != 0) {
|
while ((mi = mm_idx_reader_read(idx_rdr, n_threads)) != 0) {
|
||||||
|
int ret;
|
||||||
if ((opt.flag & MM_F_CIGAR) && (mi->flag & MM_I_NO_SEQ)) {
|
if ((opt.flag & MM_F_CIGAR) && (mi->flag & MM_I_NO_SEQ)) {
|
||||||
fprintf(stderr, "[ERROR] the prebuilt index doesn't contain sequences.\n");
|
fprintf(stderr, "[ERROR] the prebuilt index doesn't contain sequences.\n");
|
||||||
mm_idx_destroy(mi);
|
mm_idx_destroy(mi);
|
||||||
@@ -339,26 +388,46 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) {
|
if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) {
|
||||||
if (mm_idx_reader_eof(idx_rdr)) {
|
if (mm_idx_reader_eof(idx_rdr)) {
|
||||||
mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv);
|
if (opt.split_prefix == 0)
|
||||||
|
ret = mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv);
|
||||||
|
else
|
||||||
|
ret = mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv);
|
||||||
} else {
|
} else {
|
||||||
mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv);
|
ret = mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv);
|
||||||
if (opt.split_prefix == 0 && mm_verbose >= 2)
|
if (opt.split_prefix == 0 && mm_verbose >= 2)
|
||||||
fprintf(stderr, "[WARNING]\033[1;31m For a multi-part index, no @SQ lines will be outputted. Please use --split-prefix.\033[0m\n");
|
fprintf(stderr, "[WARNING]\033[1;31m For a multi-part index, no @SQ lines will be outputted. Please use --split-prefix.\033[0m\n");
|
||||||
}
|
}
|
||||||
|
if (ret != 0) {
|
||||||
|
mm_idx_destroy(mi);
|
||||||
|
mm_idx_reader_close(idx_rdr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (mm_verbose >= 3)
|
if (mm_verbose >= 3)
|
||||||
fprintf(stderr, "[M::%s::%.3f*%.2f] loaded/built the index for %d target sequence(s)\n",
|
fprintf(stderr, "[M::%s::%.3f*%.2f] loaded/built the index for %d target sequence(s)\n",
|
||||||
__func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), mi->n_seq);
|
__func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), mi->n_seq);
|
||||||
if (argc != o.ind + 1) mm_mapopt_update(&opt, mi);
|
if (argc != o.ind + 1) mm_mapopt_update(&opt, mi);
|
||||||
if (fn_bed) mm_idx_bed_read(mi, fn_bed);
|
|
||||||
if (mm_verbose >= 3) mm_idx_stat(mi);
|
if (mm_verbose >= 3) mm_idx_stat(mi);
|
||||||
|
if (junc_bed) mm_idx_bed_read(mi, junc_bed, 1);
|
||||||
|
if (alt_list) mm_idx_alt_read(mi, alt_list);
|
||||||
|
if (argc - (o.ind + 1) == 0) {
|
||||||
|
mm_idx_destroy(mi);
|
||||||
|
continue; // no query files
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
if (!(opt.flag & MM_F_FRAG_MODE)) {
|
if (!(opt.flag & MM_F_FRAG_MODE)) {
|
||||||
for (i = o.ind + 1; i < argc; ++i)
|
for (i = o.ind + 1; i < argc; ++i) {
|
||||||
mm_map_file(mi, argv[i], &opt, n_threads);
|
ret = mm_map_file(mi, argv[i], &opt, n_threads);
|
||||||
|
if (ret < 0) break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mm_map_file_frag(mi, argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_threads);
|
ret = mm_map_file_frag(mi, argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_threads);
|
||||||
}
|
}
|
||||||
mm_idx_destroy(mi);
|
mm_idx_destroy(mi);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "ERROR: failed to map the query file\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
n_parts = idx_rdr->n_parts;
|
n_parts = idx_rdr->n_parts;
|
||||||
mm_idx_reader_close(idx_rdr);
|
mm_idx_reader_close(idx_rdr);
|
||||||
@@ -367,7 +436,7 @@ int main(int argc, char *argv[])
|
|||||||
mm_split_merge(argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_parts);
|
mm_split_merge(argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_parts);
|
||||||
|
|
||||||
if (fflush(stdout) == EOF) {
|
if (fflush(stdout) == EOF) {
|
||||||
fprintf(stderr, "[ERROR] failed to write the results\n");
|
perror("[ERROR] failed to write the results");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "kthread.h"
|
#include "kthread.h"
|
||||||
#include "kvec.h"
|
#include "kvec.h"
|
||||||
#include "kalloc.h"
|
#include "kalloc.h"
|
||||||
@@ -79,49 +80,7 @@ static void collect_minimizers(void *km, const mm_mapopt_t *opt, const mm_idx_t
|
|||||||
#define heap_lt(a, b) ((a).x > (b).x)
|
#define heap_lt(a, b) ((a).x > (b).x)
|
||||||
KSORT_INIT(heap, mm128_t, heap_lt)
|
KSORT_INIT(heap, mm128_t, heap_lt)
|
||||||
|
|
||||||
typedef struct {
|
static inline int skip_seed(int flag, uint64_t r, const mm_seed_t *q, const char *qname, int qlen, const mm_idx_t *mi, int *is_self)
|
||||||
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 rep_st = 0, rep_en = 0, n_m;
|
|
||||||
size_t i;
|
|
||||||
mm_match_t *m;
|
|
||||||
*n_mini_pos = 0;
|
|
||||||
*mini_pos = (uint64_t*)kmalloc(km, mv->n * sizeof(uint64_t));
|
|
||||||
m = (mm_match_t*)kmalloc(km, mv->n * sizeof(mm_match_t));
|
|
||||||
for (i = 0, 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;
|
|
||||||
cr = mm_idx_get(mi, p->x>>8, &t);
|
|
||||||
if (t >= max_occ) {
|
|
||||||
int en = (q_pos >> 1) + 1, st = en - q_span;
|
|
||||||
if (st > rep_en) {
|
|
||||||
*rep_len += rep_en - rep_st;
|
|
||||||
rep_st = st, rep_en = en;
|
|
||||||
} else rep_en = en;
|
|
||||||
} else {
|
|
||||||
mm_match_t *q = &m[n_m++];
|
|
||||||
q->q_pos = q_pos, q->q_span = q_span, q->cr = cr, q->n = t, q->seg_id = p->y >> 32;
|
|
||||||
q->is_tandem = 0;
|
|
||||||
if (i > 0 && p->x>>8 == mv->a[i - 1].x>>8) q->is_tandem = 1;
|
|
||||||
if (i < mv->n - 1 && p->x>>8 == mv->a[i + 1].x>>8) q->is_tandem = 1;
|
|
||||||
*n_a += q->n;
|
|
||||||
(*mini_pos)[(*n_mini_pos)++] = (uint64_t)q_span<<32 | q_pos>>1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*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;
|
*is_self = 0;
|
||||||
if (qname && (flag & (MM_F_NO_DIAG|MM_F_NO_DUAL))) {
|
if (qname && (flag & (MM_F_NO_DIAG|MM_F_NO_DUAL))) {
|
||||||
@@ -150,10 +109,10 @@ static mm128_t *collect_seed_hits_heap(void *km, const mm_mapopt_t *opt, int max
|
|||||||
{
|
{
|
||||||
int i, n_m, heap_size = 0;
|
int i, n_m, heap_size = 0;
|
||||||
int64_t j, n_for = 0, n_rev = 0;
|
int64_t j, n_for = 0, n_rev = 0;
|
||||||
mm_match_t *m;
|
mm_seed_t *m;
|
||||||
mm128_t *a, *heap;
|
mm128_t *a, *heap;
|
||||||
|
|
||||||
m = collect_matches(km, &n_m, max_occ, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
m = mm_collect_matches(km, &n_m, qlen, max_occ, opt->max_max_occ, opt->occ_dist, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
||||||
|
|
||||||
heap = (mm128_t*)kmalloc(km, n_m * sizeof(mm128_t));
|
heap = (mm128_t*)kmalloc(km, n_m * sizeof(mm128_t));
|
||||||
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
||||||
@@ -167,7 +126,7 @@ static mm128_t *collect_seed_hits_heap(void *km, const mm_mapopt_t *opt, int max
|
|||||||
}
|
}
|
||||||
ks_heapmake_heap(heap_size, heap);
|
ks_heapmake_heap(heap_size, heap);
|
||||||
while (heap_size > 0) {
|
while (heap_size > 0) {
|
||||||
mm_match_t *q = &m[heap->y>>32];
|
mm_seed_t *q = &m[heap->y>>32];
|
||||||
mm128_t *p;
|
mm128_t *p;
|
||||||
uint64_t r = heap->x;
|
uint64_t r = heap->x;
|
||||||
int32_t is_self, rpos = (uint32_t)r >> 1;
|
int32_t is_self, rpos = (uint32_t)r >> 1;
|
||||||
@@ -215,12 +174,12 @@ static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ,
|
|||||||
int *n_mini_pos, uint64_t **mini_pos)
|
int *n_mini_pos, uint64_t **mini_pos)
|
||||||
{
|
{
|
||||||
int i, n_m;
|
int i, n_m;
|
||||||
mm_match_t *m;
|
mm_seed_t *m;
|
||||||
mm128_t *a;
|
mm128_t *a;
|
||||||
m = collect_matches(km, &n_m, max_occ, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
m = mm_collect_matches(km, &n_m, qlen, max_occ, opt->max_max_occ, opt->occ_dist, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
|
||||||
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
|
||||||
for (i = 0, *n_a = 0; i < n_m; ++i) {
|
for (i = 0, *n_a = 0; i < n_m; ++i) {
|
||||||
mm_match_t *q = &m[i];
|
mm_seed_t *q = &m[i];
|
||||||
const uint64_t *r = q->cr;
|
const uint64_t *r = q->cr;
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
for (k = 0; k < q->n; ++k) {
|
for (k = 0; k < q->n; ++k) {
|
||||||
@@ -231,9 +190,13 @@ static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ,
|
|||||||
if ((r[k]&1) == (q->q_pos&1)) { // forward strand
|
if ((r[k]&1) == (q->q_pos&1)) { // forward strand
|
||||||
p->x = (r[k]&0xffffffff00000000ULL) | rpos;
|
p->x = (r[k]&0xffffffff00000000ULL) | rpos;
|
||||||
p->y = (uint64_t)q->q_span << 32 | q->q_pos >> 1;
|
p->y = (uint64_t)q->q_span << 32 | q->q_pos >> 1;
|
||||||
} else { // reverse strand
|
} else if (!(opt->flag & MM_F_QSTRAND)) { // reverse strand and not in the query-strand mode
|
||||||
p->x = 1ULL<<63 | (r[k]&0xffffffff00000000ULL) | rpos;
|
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->q_span << 32 | (qlen - ((q->q_pos>>1) + 1 - q->q_span) - 1);
|
||||||
|
} else { // reverse strand; query-strand
|
||||||
|
int32_t len = mi->seq[r[k]>>32].len;
|
||||||
|
p->x = 1ULL<<63 | (r[k]&0xffffffff00000000ULL) | (len - (rpos + 1 - q->q_span) - 1); // coordinate only accurate for non-HPC seeds
|
||||||
|
p->y = (uint64_t)q->q_span << 32 | q->q_pos >> 1;
|
||||||
}
|
}
|
||||||
p->y |= (uint64_t)q->seg_id << MM_SEED_SEG_SHIFT;
|
p->y |= (uint64_t)q->seg_id << MM_SEED_SEG_SHIFT;
|
||||||
if (q->is_tandem) p->y |= MM_SEED_TANDEM;
|
if (q->is_tandem) p->y |= MM_SEED_TANDEM;
|
||||||
@@ -248,11 +211,9 @@ static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ,
|
|||||||
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_ALL_CHAINS)) { // don't choose primary mapping(s)
|
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
|
||||||
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL);
|
mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
|
||||||
if (n_segs <= 1) mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs);
|
if (n_segs <= 1) mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, 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|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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +222,7 @@ static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *k
|
|||||||
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_ALL_CHAINS)) { // don't choose primary mapping(s)
|
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
|
||||||
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL);
|
mm_set_parent(km, opt->mask_level, opt->mask_len, *n_regs, regs, opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
|
||||||
mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs);
|
mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs);
|
||||||
mm_set_sam_pri(*n_regs, regs);
|
mm_set_sam_pri(*n_regs, regs);
|
||||||
}
|
}
|
||||||
@@ -284,6 +245,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0;
|
qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0;
|
||||||
|
|
||||||
if (qlen_sum == 0 || n_segs <= 0 || n_segs > MM_MAX_SEG) return;
|
if (qlen_sum == 0 || n_segs <= 0 || n_segs > MM_MAX_SEG) return;
|
||||||
|
if (opt->max_qlen > 0 && qlen_sum > opt->max_qlen) return;
|
||||||
|
|
||||||
hash = qname? __ac_X31_hash_string(qname) : 0;
|
hash = qname? __ac_X31_hash_string(qname) : 0;
|
||||||
hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed);
|
hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed);
|
||||||
@@ -311,9 +273,25 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
if (max_chain_gap_ref < opt->max_gap) max_chain_gap_ref = opt->max_gap;
|
if (max_chain_gap_ref < opt->max_gap) max_chain_gap_ref = opt->max_gap;
|
||||||
} else max_chain_gap_ref = opt->max_gap;
|
} else max_chain_gap_ref = opt->max_gap;
|
||||||
|
|
||||||
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);
|
if (opt->flag & MM_F_RMQ) {
|
||||||
|
a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score,
|
||||||
|
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, n_a, a, &n_regs0, &u, b->km);
|
||||||
|
} else {
|
||||||
|
a = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score,
|
||||||
|
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
|
||||||
|
}
|
||||||
|
|
||||||
if (opt->max_occ > opt->mid_occ && rep_len > 0) {
|
if (opt->bw_long > opt->bw && (opt->flag & (MM_F_SPLICE|MM_F_SR|MM_F_NO_LJOIN)) == 0 && n_segs == 1 && n_regs0 > 1) { // re-chain/long-join for long sequences
|
||||||
|
int32_t st = (int32_t)a[0].y, en = (int32_t)a[(int32_t)u[0] - 1].y;
|
||||||
|
if (qlen_sum - (en - st) > opt->rmq_rescue_size || en - st > qlen_sum * opt->rmq_rescue_ratio) {
|
||||||
|
int32_t i;
|
||||||
|
for (i = 0, n_a = 0; i < n_regs0; ++i) n_a += (int32_t)u[i];
|
||||||
|
kfree(b->km, u);
|
||||||
|
radix_sort_128x(a, a + n_a);
|
||||||
|
a = mg_lchain_rmq(opt->max_gap, opt->rmq_inner_dist, opt->bw_long, opt->max_chain_skip, opt->rmq_size_cap, opt->min_cnt, opt->min_chain_score,
|
||||||
|
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, n_a, a, &n_regs0, &u, b->km);
|
||||||
|
}
|
||||||
|
} else if (opt->max_occ > opt->mid_occ && rep_len > 0 && !(opt->flag & MM_F_RMQ)) { // re-chain, mostly for short reads
|
||||||
int rechain = 0;
|
int rechain = 0;
|
||||||
if (n_regs0 > 0) { // test if the best chain has all the segments
|
if (n_regs0 > 0) { // test if the best chain has all the segments
|
||||||
int n_chained_segs = 1, max = 0, max_i = -1, max_off = -1, off = 0;
|
int n_chained_segs = 1, max = 0, max_i = -1, max_off = -1, off = 0;
|
||||||
@@ -333,13 +311,18 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
kfree(b->km, mini_pos);
|
kfree(b->km, 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);
|
if (opt->flag & MM_F_HEAP_SORT) a = collect_seed_hits_heap(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
|
||||||
else a = collect_seed_hits(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
|
else a = collect_seed_hits(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
|
||||||
a = 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 = mg_lchain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->max_chain_iter, opt->min_cnt, opt->min_chain_score,
|
||||||
|
opt->chain_gap_scale * 0.01 * mi->k, 0.0f, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b->frag_gap = max_chain_gap_ref;
|
b->frag_gap = max_chain_gap_ref;
|
||||||
b->rep_len = rep_len;
|
b->rep_len = rep_len;
|
||||||
|
|
||||||
regs0 = mm_gen_regs(b->km, hash, qlen_sum, n_regs0, u, a);
|
regs0 = mm_gen_regs(b->km, hash, qlen_sum, n_regs0, u, a, !!(opt->flag&MM_F_QSTRAND));
|
||||||
|
if (mi->n_alt) {
|
||||||
|
mm_mark_alt(mi, n_regs0, regs0);
|
||||||
|
mm_hit_sort(b->km, &n_regs0, regs0, opt->alt_drop); // this step can be merged into mm_gen_regs(); will do if this shows up in profile
|
||||||
|
}
|
||||||
|
|
||||||
if (mm_dbg_flag & MM_DBG_PRINT_SEED)
|
if (mm_dbg_flag & MM_DBG_PRINT_SEED)
|
||||||
for (j = 0; j < n_regs0; ++j)
|
for (j = 0; j < n_regs0; ++j)
|
||||||
@@ -348,10 +331,12 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x));
|
i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x));
|
||||||
|
|
||||||
chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a);
|
chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a);
|
||||||
if (!is_sr) mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos);
|
if (!is_sr && !(opt->flag&MM_F_QSTRAND))
|
||||||
|
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], &n_regs0, regs0, a);
|
regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], &n_regs0, regs0, a);
|
||||||
|
regs0 = (mm_reg1_t*)realloc(regs0, sizeof(*regs0) * n_regs0);
|
||||||
mm_set_mapq(b->km, n_regs0, regs0, opt->min_chain_score, opt->a, rep_len, is_sr);
|
mm_set_mapq(b->km, 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
|
||||||
@@ -359,7 +344,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
seg = mm_seg_gen(b->km, hash, n_segs, qlens, n_regs0, regs0, n_regs, regs, a); // split fragment chain to separate segment chains
|
seg = mm_seg_gen(b->km, hash, n_segs, qlens, n_regs0, regs0, n_regs, regs, a); // split fragment chain to separate segment chains
|
||||||
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, opt->flag&MM_F_HARD_MLEVEL); // update mm_reg1_t::parent
|
mm_set_parent(b->km, opt->mask_level, opt->mask_len, n_regs[i], regs[i], opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop); // update mm_reg1_t::parent
|
||||||
regs[i] = align_regs(opt, mi, b->km, qlens[i], seqs[i], &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(b->km, n_regs[i], regs[i], opt->min_chain_score, opt->a, rep_len, is_sr);
|
mm_set_mapq(b->km, n_regs[i], regs[i], opt->min_chain_score, opt->a, rep_len, is_sr);
|
||||||
}
|
}
|
||||||
@@ -378,7 +363,9 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
|
|||||||
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
||||||
fprintf(stderr, "QM\t%s\t%d\tcap=%ld,nCore=%ld,largest=%ld\n", qname, qlen_sum, kmst.capacity, kmst.n_cores, kmst.largest);
|
fprintf(stderr, "QM\t%s\t%d\tcap=%ld,nCore=%ld,largest=%ld\n", qname, qlen_sum, kmst.capacity, kmst.n_cores, kmst.largest);
|
||||||
assert(kmst.n_blocks == kmst.n_cores); // otherwise, there is a memory leak
|
assert(kmst.n_blocks == kmst.n_cores); // otherwise, there is a memory leak
|
||||||
if (kmst.largest > 1U<<28) {
|
if (kmst.largest > 1U<<28 || (opt->cap_kalloc > 0 && kmst.capacity > opt->cap_kalloc)) {
|
||||||
|
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
||||||
|
fprintf(stderr, "[W::%s] reset thread-local memory after read %s\n", __func__, qname);
|
||||||
km_destroy(b->km);
|
km_destroy(b->km);
|
||||||
b->km = km_init();
|
b->km = km_init();
|
||||||
}
|
}
|
||||||
@@ -397,7 +384,8 @@ mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm
|
|||||||
**************************/
|
**************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int mini_batch_size, n_processed, n_threads, n_fp;
|
int n_processed, n_threads, n_fp;
|
||||||
|
int64_t mini_batch_size;
|
||||||
const mm_mapopt_t *opt;
|
const mm_mapopt_t *opt;
|
||||||
mm_bseq_file_t **fp;
|
mm_bseq_file_t **fp;
|
||||||
const mm_idx_t *mi;
|
const mm_idx_t *mi;
|
||||||
@@ -422,10 +410,13 @@ 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;
|
int qlens[MM_MAX_SEG], j, off = s->seg_off[i], pe_ori = s->p->opt->pe_ori;
|
||||||
const char *qseqs[MM_MAX_SEG];
|
const char *qseqs[MM_MAX_SEG];
|
||||||
|
double t = 0.0;
|
||||||
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);
|
||||||
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);
|
||||||
|
t = realtime();
|
||||||
|
}
|
||||||
for (j = 0; j < s->n_seg[i]; ++j) {
|
for (j = 0; j < s->n_seg[i]; ++j) {
|
||||||
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))))
|
||||||
mm_revcomp_bseq(&s->seq[off + j]);
|
mm_revcomp_bseq(&s->seq[off + j]);
|
||||||
@@ -457,6 +448,8 @@ static void worker_for(void *_data, long i, int tid) // kt_for() callback
|
|||||||
r->rev = !r->rev;
|
r->rev = !r->rev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
|
||||||
|
fprintf(stderr, "QT\t%s\t%d\t%.6f\n", s->seq[off].name, tid, realtime() - t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void merge_hits(step_t *s)
|
static void merge_hits(step_t *s)
|
||||||
@@ -501,8 +494,16 @@ static void merge_hits(step_t *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mm_hit_sort(km, &s->n_reg[k], s->reg[k]);
|
if (!(opt->flag&MM_F_SR) && s->seq[k].l_seq >= opt->rank_min_len)
|
||||||
mm_set_parent(km, opt->mask_level, s->n_reg[k], s->reg[k], opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL);
|
mm_update_dp_max(s->seq[k].l_seq, s->n_reg[k], s->reg[k], opt->rank_frac, opt->a, opt->b);
|
||||||
|
for (j = 0; j < s->n_reg[k]; ++j) {
|
||||||
|
mm_reg1_t *r = &s->reg[k][j];
|
||||||
|
if (r->p) r->p->dp_max2 = 0; // reset ->dp_max2 as mm_set_parent() doesn't clear it; necessary with mm_update_dp_max()
|
||||||
|
r->subsc = 0; // this may not be necessary
|
||||||
|
r->n_sub = 0; // n_sub will be an underestimate as we don't see all the chains now, but it can't be accurate anyway
|
||||||
|
}
|
||||||
|
mm_hit_sort(km, &s->n_reg[k], s->reg[k], opt->alt_drop);
|
||||||
|
mm_set_parent(km, opt->mask_level, opt->mask_len, s->n_reg[k], s->reg[k], opt->a * 2 + opt->b, opt->flag&MM_F_HARD_MLEVEL, opt->alt_drop);
|
||||||
if (!(opt->flag & MM_F_ALL_CHAINS)) {
|
if (!(opt->flag & MM_F_ALL_CHAINS)) {
|
||||||
mm_select_sub(km, opt->pri_ratio, s->p->mi->k*2, opt->best_n, &s->n_reg[k], s->reg[k]);
|
mm_select_sub(km, opt->pri_ratio, s->p->mi->k*2, opt->best_n, &s->n_reg[k], s->reg[k]);
|
||||||
mm_set_sam_pri(s->n_reg[k], s->reg[k]);
|
mm_set_sam_pri(s->n_reg[k], s->reg[k]);
|
||||||
@@ -583,16 +584,16 @@ static void *worker_pipeline(void *shared, int step, void *in)
|
|||||||
if ((p->opt->flag & MM_F_NO_PRINT_2ND) && r->id != r->parent)
|
if ((p->opt->flag & MM_F_NO_PRINT_2ND) && r->id != r->parent)
|
||||||
continue;
|
continue;
|
||||||
if (p->opt->flag & MM_F_OUT_SAM)
|
if (p->opt->flag & MM_F_OUT_SAM)
|
||||||
mm_write_sam2(&p->str, mi, t, i - seg_st, j, s->n_seg[k], &s->n_reg[seg_st], (const mm_reg1_t*const*)&s->reg[seg_st], km, p->opt->flag);
|
mm_write_sam3(&p->str, mi, t, i - seg_st, j, s->n_seg[k], &s->n_reg[seg_st], (const mm_reg1_t*const*)&s->reg[seg_st], km, p->opt->flag, s->rep_len[i]);
|
||||||
else
|
else
|
||||||
mm_write_paf(&p->str, mi, t, r, km, p->opt->flag);
|
mm_write_paf3(&p->str, mi, t, r, km, p->opt->flag, s->rep_len[i]);
|
||||||
mm_err_puts(p->str.s);
|
mm_err_puts(p->str.s);
|
||||||
}
|
}
|
||||||
} else if (p->opt->flag & (MM_F_OUT_SAM|MM_F_PAF_NO_HIT)) { // output an empty hit, if requested
|
} else if ((p->opt->flag & MM_F_PAF_NO_HIT) || ((p->opt->flag & MM_F_OUT_SAM) && !(p->opt->flag & MM_F_SAM_HIT_ONLY))) { // output an empty hit, if requested
|
||||||
if (p->opt->flag & MM_F_OUT_SAM)
|
if (p->opt->flag & MM_F_OUT_SAM)
|
||||||
mm_write_sam2(&p->str, mi, t, i - seg_st, -1, s->n_seg[k], &s->n_reg[seg_st], (const mm_reg1_t*const*)&s->reg[seg_st], km, p->opt->flag);
|
mm_write_sam3(&p->str, mi, t, i - seg_st, -1, s->n_seg[k], &s->n_reg[seg_st], (const mm_reg1_t*const*)&s->reg[seg_st], km, p->opt->flag, s->rep_len[i]);
|
||||||
else
|
else
|
||||||
mm_write_paf(&p->str, mi, t, 0, 0, p->opt->flag);
|
mm_write_paf3(&p->str, mi, t, 0, 0, p->opt->flag, s->rep_len[i]);
|
||||||
mm_err_puts(p->str.s);
|
mm_err_puts(p->str.s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,7 +622,7 @@ static mm_bseq_file_t **open_bseqs(int n, const char **fn)
|
|||||||
for (i = 0; i < n; ++i) {
|
for (i = 0; i < n; ++i) {
|
||||||
if ((fp[i] = mm_bseq_open(fn[i])) == 0) {
|
if ((fp[i] = mm_bseq_open(fn[i])) == 0) {
|
||||||
if (mm_verbose >= 1)
|
if (mm_verbose >= 1)
|
||||||
fprintf(stderr, "ERROR: failed to open file '%s'\n", fn[i]);
|
fprintf(stderr, "ERROR: failed to open file '%s': %s\n", fn[i], strerror(errno));
|
||||||
for (j = 0; j < i; ++j)
|
for (j = 0; j < i; ++j)
|
||||||
mm_bseq_close(fp[j]);
|
mm_bseq_close(fp[j]);
|
||||||
free(fp);
|
free(fp);
|
||||||
|
|||||||
@@ -35,6 +35,10 @@
|
|||||||
#define MM_F_PAF_NO_HIT 0x8000000 // output unmapped reads to PAF
|
#define MM_F_PAF_NO_HIT 0x8000000 // output unmapped reads to PAF
|
||||||
#define MM_F_NO_END_FLT 0x10000000
|
#define MM_F_NO_END_FLT 0x10000000
|
||||||
#define MM_F_HARD_MLEVEL 0x20000000
|
#define MM_F_HARD_MLEVEL 0x20000000
|
||||||
|
#define MM_F_SAM_HIT_ONLY 0x40000000
|
||||||
|
#define MM_F_RMQ (0x80000000LL)
|
||||||
|
#define MM_F_QSTRAND (0x100000000LL)
|
||||||
|
#define MM_F_NO_INV (0x200000000LL)
|
||||||
|
|
||||||
#define MM_I_HPC 0x1
|
#define MM_I_HPC 0x1
|
||||||
#define MM_I_NO_SEQ 0x2
|
#define MM_I_NO_SEQ 0x2
|
||||||
@@ -44,6 +48,18 @@
|
|||||||
|
|
||||||
#define MM_MAX_SEG 255
|
#define MM_MAX_SEG 255
|
||||||
|
|
||||||
|
#define MM_CIGAR_MATCH 0
|
||||||
|
#define MM_CIGAR_INS 1
|
||||||
|
#define MM_CIGAR_DEL 2
|
||||||
|
#define MM_CIGAR_N_SKIP 3
|
||||||
|
#define MM_CIGAR_SOFTCLIP 4
|
||||||
|
#define MM_CIGAR_HARDCLIP 5
|
||||||
|
#define MM_CIGAR_PADDING 6
|
||||||
|
#define MM_CIGAR_EQ_MATCH 7
|
||||||
|
#define MM_CIGAR_X_MISMATCH 8
|
||||||
|
|
||||||
|
#define MM_CIGAR_STR "MIDNSHP=XB"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -57,23 +73,18 @@ typedef struct {
|
|||||||
char *name; // name of the db sequence
|
char *name; // name of the db sequence
|
||||||
uint64_t offset; // offset in mm_idx_t::S
|
uint64_t offset; // offset in mm_idx_t::S
|
||||||
uint32_t len; // length
|
uint32_t len; // length
|
||||||
|
uint32_t is_alt;
|
||||||
} mm_idx_seq_t;
|
} mm_idx_seq_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t x;
|
|
||||||
int32_t end, idx;
|
|
||||||
int32_t score; // NB: wasting 4 bytes due to memory alignment
|
|
||||||
} mm_idx_bed_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t b, w, k, flag;
|
int32_t b, w, k, flag;
|
||||||
uint32_t n_seq; // number of reference sequences
|
uint32_t n_seq; // number of reference sequences
|
||||||
int32_t index;
|
int32_t index;
|
||||||
uint32_t n_R;
|
int32_t n_alt;
|
||||||
mm_idx_seq_t *seq; // sequence name, length and offset
|
mm_idx_seq_t *seq; // sequence name, length and offset
|
||||||
uint32_t *S; // 4-bit packed sequence
|
uint32_t *S; // 4-bit packed sequence
|
||||||
struct mm_idx_bucket_s *B; // index (hidden)
|
struct mm_idx_bucket_s *B; // index (hidden)
|
||||||
mm_idx_bed_t *R;
|
struct mm_idx_intv_s *I; // intervals (hidden)
|
||||||
void *km, *h;
|
void *km, *h;
|
||||||
} mm_idx_t;
|
} mm_idx_t;
|
||||||
|
|
||||||
@@ -97,7 +108,7 @@ typedef struct {
|
|||||||
int32_t mlen, blen; // seeded exact match length; seeded alignment block length
|
int32_t mlen, blen; // seeded exact match length; seeded alignment block length
|
||||||
int32_t n_sub; // number of suboptimal mappings
|
int32_t n_sub; // number of suboptimal mappings
|
||||||
int32_t score0; // initial chaining score (before chain merging/spliting)
|
int32_t score0; // initial chaining score (before chain merging/spliting)
|
||||||
uint32_t mapq:8, split:2, rev:1, inv:1, sam_pri:1, proper_frag:1, pe_thru:1, seg_split:1, seg_id:8, split_inv:1, dummy:7;
|
uint32_t mapq:8, split:2, rev:1, inv:1, sam_pri:1, proper_frag:1, pe_thru:1, seg_split:1, seg_id:8, split_inv:1, is_alt:1, dummy:6;
|
||||||
uint32_t hash;
|
uint32_t hash;
|
||||||
float div;
|
float div;
|
||||||
mm_extra_t *p;
|
mm_extra_t *p;
|
||||||
@@ -106,33 +117,39 @@ typedef struct {
|
|||||||
// indexing and mapping options
|
// indexing and mapping options
|
||||||
typedef struct {
|
typedef struct {
|
||||||
short k, w, flag, bucket_bits;
|
short k, w, flag, bucket_bits;
|
||||||
int mini_batch_size;
|
int64_t mini_batch_size;
|
||||||
uint64_t batch_size;
|
uint64_t batch_size;
|
||||||
} mm_idxopt_t;
|
} mm_idxopt_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
int64_t flag; // see MM_F_* macros
|
||||||
int seed;
|
int seed;
|
||||||
int sdust_thres; // score threshold for SDUST; 0 to disable
|
int sdust_thres; // score threshold for SDUST; 0 to disable
|
||||||
int flag; // see MM_F_* macros
|
|
||||||
|
|
||||||
int bw; // bandwidth
|
int max_qlen; // max query length
|
||||||
|
|
||||||
|
int bw, bw_long; // bandwidth
|
||||||
int max_gap, max_gap_ref; // break a chain if there are no minimizers in a max_gap window
|
int max_gap, max_gap_ref; // break a chain if there are no minimizers in a max_gap window
|
||||||
int max_frag_len;
|
int max_frag_len;
|
||||||
int max_chain_skip;
|
int max_chain_skip, max_chain_iter;
|
||||||
int min_cnt; // min number of minimizers on each chain
|
int min_cnt; // min number of minimizers on each chain
|
||||||
int min_chain_score; // min chaining score
|
int min_chain_score; // min chaining score
|
||||||
|
float chain_gap_scale;
|
||||||
|
int rmq_size_cap, rmq_inner_dist;
|
||||||
|
int rmq_rescue_size;
|
||||||
|
float rmq_rescue_ratio;
|
||||||
|
|
||||||
float mask_level;
|
float mask_level;
|
||||||
|
int mask_len;
|
||||||
float pri_ratio;
|
float pri_ratio;
|
||||||
int best_n; // top best_n chains are subjected to DP alignment
|
int best_n; // top best_n chains are subjected to DP alignment
|
||||||
|
|
||||||
int max_join_long, max_join_short;
|
float alt_drop;
|
||||||
int min_join_flank_sc;
|
|
||||||
float min_join_flank_ratio;
|
|
||||||
|
|
||||||
int a, b, q, e, q2, e2; // matching score, mismatch, gap-open and gap-ext penalties
|
int a, b, q, e, q2, e2; // matching score, mismatch, gap-open and gap-ext penalties
|
||||||
int sc_ambi; // score when one or both bases are "N"
|
int sc_ambi; // score when one or both bases are "N"
|
||||||
int noncan; // cost of non-canonical splicing sites
|
int noncan; // cost of non-canonical splicing sites
|
||||||
|
int junc_bonus;
|
||||||
int zdrop, zdrop_inv; // break alignment if alignment score drops too fast along the diagonal
|
int zdrop, zdrop_inv; // break alignment if alignment score drops too fast along the diagonal
|
||||||
int end_bonus;
|
int end_bonus;
|
||||||
int min_dp_max; // drop an alignment if the score of the max scoring segment is below this threshold
|
int min_dp_max; // drop an alignment if the score of the max scoring segment is below this threshold
|
||||||
@@ -140,13 +157,18 @@ typedef struct {
|
|||||||
int anchor_ext_len, anchor_ext_shift;
|
int anchor_ext_len, anchor_ext_shift;
|
||||||
float max_clip_ratio; // drop an alignment if BOTH ends are clipped above this ratio
|
float max_clip_ratio; // drop an alignment if BOTH ends are clipped above this ratio
|
||||||
|
|
||||||
|
int rank_min_len;
|
||||||
|
float rank_frac;
|
||||||
|
|
||||||
int pe_ori, pe_bonus;
|
int pe_ori, pe_bonus;
|
||||||
|
|
||||||
float mid_occ_frac; // only used by mm_mapopt_update(); see below
|
float mid_occ_frac; // only used by mm_mapopt_update(); see below
|
||||||
int32_t min_mid_occ;
|
int32_t min_mid_occ, max_mid_occ;
|
||||||
int32_t mid_occ; // ignore seeds with occurrences above this threshold
|
int32_t mid_occ; // ignore seeds with occurrences above this threshold
|
||||||
int32_t max_occ;
|
int32_t max_occ, max_max_occ, occ_dist;
|
||||||
int mini_batch_size; // size of a batch of query bases to process in parallel
|
int64_t mini_batch_size; // size of a batch of query bases to process in parallel
|
||||||
|
int64_t max_sw_mat;
|
||||||
|
int64_t cap_kalloc;
|
||||||
|
|
||||||
const char *split_prefix;
|
const char *split_prefix;
|
||||||
} mm_mapopt_t;
|
} mm_mapopt_t;
|
||||||
@@ -370,10 +392,9 @@ int mm_idx_index_name(mm_idx_t *mi);
|
|||||||
int mm_idx_name2id(const mm_idx_t *mi, const char *name);
|
int mm_idx_name2id(const mm_idx_t *mi, const char *name);
|
||||||
int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq);
|
int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq);
|
||||||
|
|
||||||
// BED operations
|
int mm_idx_alt_read(mm_idx_t *mi, const char *fn);
|
||||||
int mm_idx_bed_read(mm_idx_t *mi, const char *fn);
|
int mm_idx_bed_read(mm_idx_t *mi, const char *fn, int read_junc);
|
||||||
int mm_idx_bed_attach(mm_idx_t *mi, uint32_t n, mm_idx_bed_t *r);
|
int mm_idx_bed_junc(const mm_idx_t *mi, int32_t ctg, int32_t st, int32_t en, uint8_t *s);
|
||||||
int mm_idx_bed_query(const mm_idx_t *mi, uint64_t x);
|
|
||||||
|
|
||||||
// deprecated APIs for backward compatibility
|
// deprecated APIs for backward compatibility
|
||||||
void mm_mapopt_init(mm_mapopt_t *opt);
|
void mm_mapopt_init(mm_mapopt_t *opt);
|
||||||
|
|||||||
+138
-54
@@ -1,4 +1,4 @@
|
|||||||
.TH minimap2 1 "11 October 2018" "minimap2-2.13 (r850)" "Bioinformatics tools"
|
.TH minimap2 1 "7 August 2021" "minimap2-2.22 (r1101)" "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
|
||||||
@@ -121,6 +121,14 @@ provided as the target sequences, options
|
|||||||
.BR -w ,
|
.BR -w ,
|
||||||
.B -I
|
.B -I
|
||||||
will be effectively overridden by the options stored in the index file.
|
will be effectively overridden by the options stored in the index file.
|
||||||
|
.TP
|
||||||
|
.BI --alt \ FILE
|
||||||
|
List of ALT contigs [null]
|
||||||
|
.TP
|
||||||
|
.BI --alt-drop \ FLOAT
|
||||||
|
Drop ALT hits by
|
||||||
|
.I FLOAT
|
||||||
|
fraction when ranking and computing mapping quality [0.15]
|
||||||
.SS Mapping options
|
.SS Mapping options
|
||||||
.TP 10
|
.TP 10
|
||||||
.BI -f \ FLOAT | INT1 [, INT2 ]
|
.BI -f \ FLOAT | INT1 [, INT2 ]
|
||||||
@@ -137,22 +145,32 @@ or
|
|||||||
.B -xsr
|
.B -xsr
|
||||||
mode, which sets the threshold for a second round of seeding.
|
mode, which sets the threshold for a second round of seeding.
|
||||||
.TP
|
.TP
|
||||||
.BI --min-occ-floor \ INT
|
.BI -U \ INT1 [, INT2 ]
|
||||||
Force minimap2 to always use k-mers occurring
|
Lower and upper bounds of k-mer occurrences [10,1000000]. The final k-mer occurrence threshold is
|
||||||
|
.RI max{ INT1 ,\ min{ INT2 ,
|
||||||
|
.BR -f }}.
|
||||||
|
This option prevents excessively small or large
|
||||||
|
.B -f
|
||||||
|
estimated from the input reference. It deprecates
|
||||||
|
.B --min-occ-floor
|
||||||
|
in earlier versions of minimap2.
|
||||||
|
.TP
|
||||||
|
.BI -e \ INT
|
||||||
|
Sample a high-frequency minimizer every
|
||||||
.I INT
|
.I INT
|
||||||
times or less [0]. In effect, the max occurrence threshold is set to
|
basepairs [500].
|
||||||
the
|
|
||||||
.RI max{ INT ,
|
|
||||||
.BR -f }.
|
|
||||||
.TP
|
.TP
|
||||||
.BI -g \ INT
|
.BI -g \ NUM
|
||||||
Stop chain enlongation if there are no minimizers within
|
Stop chain enlongation if there are no minimizers within
|
||||||
.IR INT -bp
|
.IR NUM -bp
|
||||||
[10000].
|
[10k].
|
||||||
.TP
|
.TP
|
||||||
.BI -r \ INT
|
.BI -r \ NUM1 [, NUM2 ]
|
||||||
Bandwidth used in chaining and DP-based alignment [500]. This option
|
Bandwidth for chaining and base alignment [500,20k].
|
||||||
approximately controls the maximum gap size.
|
.I NUM1
|
||||||
|
is used for initial chaining and alignment extension;
|
||||||
|
.I NUM2
|
||||||
|
for RMQ-based re-chaining and closing gaps in alignments.
|
||||||
.TP
|
.TP
|
||||||
.BI -n \ INT
|
.BI -n \ INT
|
||||||
Discard chains consisting of
|
Discard chains consisting of
|
||||||
@@ -226,28 +244,44 @@ Mark as secondary a chain that overlaps with a better chain by
|
|||||||
.I FLOAT
|
.I FLOAT
|
||||||
or more of the shorter chain [0.5]
|
or more of the shorter chain [0.5]
|
||||||
.TP
|
.TP
|
||||||
|
.BR --rmq = no | yes
|
||||||
|
Use the minigraph chaining algorithm [no]. The minigraph algorithm is better
|
||||||
|
for aligning contigs through long INDELs.
|
||||||
|
.TP
|
||||||
.B --hard-mask-level
|
.B --hard-mask-level
|
||||||
Honor option
|
Honor option
|
||||||
.B -M
|
.B -M
|
||||||
and disable a heurstic to save unmapped subsequences.
|
and disable a heurstic to save unmapped subsequences and disables
|
||||||
|
.BR --mask-len .
|
||||||
|
.TP
|
||||||
|
.BI --mask-len \ NUM
|
||||||
|
Keep an alignment if dropping it leaves an unaligned region on query longer than
|
||||||
|
.IR INT
|
||||||
|
[inf]. Effective without
|
||||||
|
.BR --hard-mask-level .
|
||||||
.TP
|
.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 [25]. 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
|
||||||
option makes minimap2 exits the inner loop if it repeatedly sees seeds already
|
option makes minimap2 exits the inner loop if it repeatedly sees seeds already
|
||||||
on chains. Set
|
on chains. Set
|
||||||
.I INT
|
.I INT
|
||||||
to a large number to switch off this heurstics.
|
to a large number to switch off this heurstics.
|
||||||
.TP
|
.TP
|
||||||
|
.BI --max-chain-iter \ INT
|
||||||
|
Check up to
|
||||||
|
.I INT
|
||||||
|
partial chains during chaining [5000]. This is a heuristic to avoid quadratic
|
||||||
|
time complexity in the worst case.
|
||||||
|
.TP
|
||||||
|
.BI --chain-gap-scale \ FLOAT
|
||||||
|
Scale of gap cost during chaining [1.0]
|
||||||
|
.TP
|
||||||
.B --no-long-join
|
.B --no-long-join
|
||||||
Disable the long gap patching heuristic. When this option is applied, the
|
Disable the long gap patching heuristic. When this option is applied, the
|
||||||
maximum alignment gap is mostly controlled by
|
maximum alignment gap is mostly controlled by
|
||||||
.BR -r .
|
.BR -r .
|
||||||
.TP
|
.TP
|
||||||
.BI --lj-min-ratio \ FLOAT
|
|
||||||
Fraction of query sequence length required to bridge a long gap [0.5]. A
|
|
||||||
smaller value helps to recover longer gaps, at the cost of more false gaps.
|
|
||||||
.TP
|
|
||||||
.B --splice
|
.B --splice
|
||||||
Enable the splice alignment mode.
|
Enable the splice alignment mode.
|
||||||
.TP
|
.TP
|
||||||
@@ -274,6 +308,10 @@ Only map to the reverse complement strand of the reference sequences.
|
|||||||
.BR --heap-sort = no | yes
|
.BR --heap-sort = no | yes
|
||||||
If yes, sort anchors with heap merge, instead of radix sort. Heap merge is
|
If yes, sort anchors with heap merge, instead of radix sort. Heap merge is
|
||||||
faster for short reads, but slower for long reads. [no]
|
faster for short reads, but slower for long reads. [no]
|
||||||
|
.TP
|
||||||
|
.B --no-pairing
|
||||||
|
Treat two reads in a pair as independent reads. The mate related fields in SAM
|
||||||
|
are still properly populated.
|
||||||
.SS Alignment options
|
.SS Alignment options
|
||||||
.TP 10
|
.TP 10
|
||||||
.BI -A \ INT
|
.BI -A \ INT
|
||||||
@@ -354,6 +392,17 @@ on SIRV data, please add
|
|||||||
.B --splice-flank=no
|
.B --splice-flank=no
|
||||||
to the command line.
|
to the command line.
|
||||||
.TP
|
.TP
|
||||||
|
.BR --junc-bed \ FILE
|
||||||
|
Gene annotations in the BED12 format (aka 12-column BED), or intron positions
|
||||||
|
in 5-column BED. With this option, minimap2 prefers splicing in annotations.
|
||||||
|
BED12 file can be converted from GTF/GFF3 with `paftools.js gff2bed anno.gtf'
|
||||||
|
[].
|
||||||
|
.TP
|
||||||
|
.BR --junc-bonus \ INT
|
||||||
|
Score bonus for a splice donor or acceptor found in annotation (effective with
|
||||||
|
.BR --junc-bed )
|
||||||
|
[9].
|
||||||
|
.TP
|
||||||
.BI --end-seed-pen \ INT
|
.BI --end-seed-pen \ INT
|
||||||
Drop a terminal anchor if
|
Drop a terminal anchor if
|
||||||
.IR s <log( g )+ INT ,
|
.IR s <log( g )+ INT ,
|
||||||
@@ -369,12 +418,27 @@ It helps to avoid tiny terminal exons. [6]
|
|||||||
.B --no-end-flt
|
.B --no-end-flt
|
||||||
Don't filter seeds towards the ends of chains before performing base-level
|
Don't filter seeds towards the ends of chains before performing base-level
|
||||||
alignment.
|
alignment.
|
||||||
|
.TP
|
||||||
|
.BI --cap-sw-mem \ NUM
|
||||||
|
Skip alignment if the DP matrix size is above
|
||||||
|
.IR NUM .
|
||||||
|
Set 0 to disable [100m].
|
||||||
|
.TP
|
||||||
|
.BI --cap-kalloc \ NUM
|
||||||
|
Free thread-local kalloc memory reservoir if after the alignment the size of the reservoir above
|
||||||
|
.IR NUM .
|
||||||
|
Set 0 to disable [0].
|
||||||
.SS Input/output options
|
.SS Input/output options
|
||||||
.TP 10
|
.TP 10
|
||||||
.B -a
|
.B -a
|
||||||
Generate CIGAR and output alignments in the SAM format. Minimap2 outputs in PAF
|
Generate CIGAR and output alignments in the SAM format. Minimap2 outputs in PAF
|
||||||
by default.
|
by default.
|
||||||
.TP
|
.TP
|
||||||
|
.BI -o \ FILE
|
||||||
|
Output alignments to
|
||||||
|
.I FILE
|
||||||
|
[stdout].
|
||||||
|
.TP
|
||||||
.B -Q
|
.B -Q
|
||||||
Ignore base quality in the input file.
|
Ignore base quality in the input file.
|
||||||
.TP
|
.TP
|
||||||
@@ -449,6 +513,18 @@ memory.
|
|||||||
.BR --secondary = yes | no
|
.BR --secondary = yes | no
|
||||||
Whether to output secondary alignments [yes]
|
Whether to output secondary alignments [yes]
|
||||||
.TP
|
.TP
|
||||||
|
.BI --max-qlen \ NUM
|
||||||
|
Filter out query sequences longer than
|
||||||
|
.IR NUM .
|
||||||
|
.TP
|
||||||
|
.B --paf-no-hit
|
||||||
|
In PAF, output unmapped queries; the strand and the reference name fields are
|
||||||
|
set to `*'. Warning: some paftools.js commands may not work with such output
|
||||||
|
for the moment.
|
||||||
|
.TP
|
||||||
|
.B --sam-hit-only
|
||||||
|
In SAM, don't output unmapped reads.
|
||||||
|
.TP
|
||||||
.B --version
|
.B --version
|
||||||
Print version number to stdout
|
Print version number to stdout
|
||||||
.SS Preset options
|
.SS Preset options
|
||||||
@@ -462,60 +538,47 @@ Available
|
|||||||
.I STR
|
.I STR
|
||||||
are:
|
are:
|
||||||
.RS
|
.RS
|
||||||
.TP 8
|
.TP 10
|
||||||
.B map-pb
|
|
||||||
PacBio/Oxford Nanopore read to reference mapping
|
|
||||||
.RB ( -Hk19 )
|
|
||||||
.TP
|
|
||||||
.B map-ont
|
.B map-ont
|
||||||
Slightly more sensitive for Oxford Nanopore to reference mapping
|
Align noisy long reads of ~10% error rate to a reference genome. This is the
|
||||||
.RB ( -k15 ).
|
default mode.
|
||||||
For PacBio reads, HPC minimizers consistently leads to faster performance and
|
.TP
|
||||||
more sensitive results in comparison to normal minimizers. For Oxford Nanopore
|
.B map-hifi
|
||||||
data, normal minimizers are better, though not much. The effectiveness of HPC
|
Align PacBio high-fidelity (HiFi) reads to a reference genome
|
||||||
is determined by the sequencing error mode.
|
.RB ( -k19
|
||||||
|
.B -w19 -U50,500 -g10k -A1 -B4 -O6,26 -E2,1
|
||||||
|
.BR -s200 ).
|
||||||
|
.TP
|
||||||
|
.B map-pb
|
||||||
|
Align older PacBio continuous long (CLR) reads to a reference genome
|
||||||
|
.RB ( -Hk19 ).
|
||||||
.TP
|
.TP
|
||||||
.B asm5
|
.B asm5
|
||||||
Long assembly to reference mapping
|
Long assembly to reference mapping
|
||||||
.RB ( -k19
|
.RB ( -k19
|
||||||
.B -w19 -A1 -B19 -O39,81 -E3,1 -s200 -z200
|
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B19 -O39,81 -E3,1 -s200 -z200
|
||||||
.BR --min-occ-floor=100 ).
|
.BR -N50 ).
|
||||||
Typically, the alignment will not extend to regions with 5% or higher sequence
|
Typically, the alignment will not extend to regions with 5% or higher sequence
|
||||||
divergence. Only use this preset if the average divergence is far below 5%.
|
divergence. Only use this preset if the average divergence is far below 5%.
|
||||||
.TP
|
.TP
|
||||||
.B asm10
|
.B asm10
|
||||||
Long assembly to reference mapping
|
Long assembly to reference mapping
|
||||||
.RB ( -k19
|
.RB ( -k19
|
||||||
.B -w19 -A1 -B9 -O16,41 -E2,1 -s200 -z200
|
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B9 -O16,41 -E2,1 -s200 -z200
|
||||||
.BR --min-occ-floor=100 ).
|
.BR -N50 ).
|
||||||
Up to 10% sequence divergence.
|
Up to 10% sequence divergence.
|
||||||
.TP
|
.TP
|
||||||
.B asm20
|
.B asm20
|
||||||
Long assembly to reference mapping
|
Long assembly to reference mapping
|
||||||
.RB ( -k19
|
.RB ( -k19
|
||||||
.B -w10 -A1 -B6 -O6,26 -E2,1 -s200 -z200
|
.B -w10 -U50,500 --rmq -r100k -g10k -A1 -B4 -O6,26 -E2,1 -s200 -z200
|
||||||
.BR --min-occ-floor=100 ).
|
.BR -N50 ).
|
||||||
Up to 20% sequence divergence.
|
Up to 20% sequence divergence.
|
||||||
.TP
|
.TP
|
||||||
.B ava-pb
|
|
||||||
PacBio all-vs-all overlap mapping
|
|
||||||
.RB ( -Hk19
|
|
||||||
.B -Xw5 -m100 -g10000 --max-chain-skip
|
|
||||||
.BR 25 ).
|
|
||||||
.TP
|
|
||||||
.B ava-ont
|
|
||||||
Oxford Nanopore all-vs-all overlap mapping
|
|
||||||
.RB ( -k15
|
|
||||||
.B -Xw5 -m100 -g10000 -r2000 --max-chain-skip
|
|
||||||
.BR 25 ).
|
|
||||||
Similarly, the major difference from
|
|
||||||
.B ava-pb
|
|
||||||
is that this preset is not using HPC minimizers.
|
|
||||||
.TP
|
|
||||||
.B splice
|
.B splice
|
||||||
Long-read spliced alignment
|
Long-read spliced alignment
|
||||||
.RB ( -k15
|
.RB ( -k15
|
||||||
.B -w5 --splice -g2000 -G200k -A1 -B2 -O2,32 -E1,0 -C9 -z200 -ub
|
.B -w5 --splice -g2k -G200k -A1 -B2 -O2,32 -E1,0 -b0 -C9 -z200 -ub --junc-bonus=9 --cap-sw-mem=0
|
||||||
.BR --splice-flank=yes ).
|
.BR --splice-flank=yes ).
|
||||||
In the splice mode, 1) long deletions are taken as introns and represented as
|
In the splice mode, 1) long deletions are taken as introns and represented as
|
||||||
the
|
the
|
||||||
@@ -525,12 +588,30 @@ costs are different during chaining; 4) the computation of the
|
|||||||
.RB ` ms '
|
.RB ` ms '
|
||||||
tag ignores introns to demote hits to pseudogenes.
|
tag ignores introns to demote hits to pseudogenes.
|
||||||
.TP
|
.TP
|
||||||
|
.B splice:hq
|
||||||
|
Long-read splice alignment for PacBio CCS reads
|
||||||
|
.RB ( -xsplice
|
||||||
|
.B -C5 -O6,24
|
||||||
|
.BR -B4 ).
|
||||||
|
.TP
|
||||||
.B sr
|
.B sr
|
||||||
Short single-end reads without splicing
|
Short single-end reads without splicing
|
||||||
.RB ( -k21
|
.RB ( -k21
|
||||||
.B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -r50 -p.5 -N20 -f1000,5000 -n2 -m20
|
.B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -b0 -r100 -p.5 -N20 -f1000,5000 -n2 -m20
|
||||||
.B -s40 -g200 -2K50m --heap-sort=yes
|
.B -s40 -g100 -2K50m --heap-sort=yes
|
||||||
.BR --secondary=no ).
|
.BR --secondary=no ).
|
||||||
|
.TP
|
||||||
|
.B ava-pb
|
||||||
|
PacBio CLR all-vs-all overlap mapping
|
||||||
|
.RB ( -Hk19
|
||||||
|
.B -Xw5 -e0
|
||||||
|
.BR -m100 ).
|
||||||
|
.TP
|
||||||
|
.B ava-ont
|
||||||
|
Oxford Nanopore all-vs-all overlap mapping
|
||||||
|
.RB ( -k15
|
||||||
|
.B -Xw5 -e0 -m100
|
||||||
|
.BR -r2k ).
|
||||||
.RE
|
.RE
|
||||||
.SS Miscellaneous options
|
.SS Miscellaneous options
|
||||||
.TP 10
|
.TP 10
|
||||||
@@ -589,12 +670,15 @@ s2 i Chaining score of the best secondary chain
|
|||||||
NM i Total number of mismatches and gaps in the alignment
|
NM i Total number of mismatches and gaps in the alignment
|
||||||
MD Z To generate the ref sequence in the alignment
|
MD Z To generate the ref sequence in the alignment
|
||||||
AS i DP alignment score
|
AS i DP alignment score
|
||||||
|
SA Z List of other supplementary alignments
|
||||||
ms i DP score of the max scoring segment in the alignment
|
ms i DP score of the max scoring segment in the alignment
|
||||||
nn i Number of ambiguous bases in the alignment
|
nn i Number of ambiguous bases in the alignment
|
||||||
ts A Transcript strand (splice mode only)
|
ts A Transcript strand (splice mode only)
|
||||||
cg Z CIGAR string (only in PAF)
|
cg Z CIGAR string (only in PAF)
|
||||||
cs Z Difference string
|
cs Z Difference string
|
||||||
dv f Approximate per-base sequence divergence
|
dv f Approximate per-base sequence divergence
|
||||||
|
de f Gap-compressed per-base sequence divergence
|
||||||
|
rl i Length of query regions harboring repetitive seeds
|
||||||
.TE
|
.TE
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
|
|||||||
@@ -116,8 +116,7 @@ long peakrss(void)
|
|||||||
double realtime(void)
|
double realtime(void)
|
||||||
{
|
{
|
||||||
struct timeval tp;
|
struct timeval tp;
|
||||||
struct timezone tzp;
|
gettimeofday(&tp, NULL);
|
||||||
gettimeofday(&tp, &tzp);
|
|
||||||
return tp.tv_sec + tp.tv_usec * 1e-6;
|
return tp.tv_sec + tp.tv_usec * 1e-6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +125,7 @@ void mm_err_puts(const char *str)
|
|||||||
int ret;
|
int ret;
|
||||||
ret = puts(str);
|
ret = puts(str);
|
||||||
if (ret == EOF) {
|
if (ret == EOF) {
|
||||||
fprintf(stderr, "[ERROR] failed to write the results\n");
|
perror("[ERROR] failed to write the results");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +135,7 @@ void mm_err_fwrite(const void *p, size_t size, size_t nitems, FILE *fp)
|
|||||||
int ret;
|
int ret;
|
||||||
ret = fwrite(p, size, nitems, fp);
|
ret = fwrite(p, size, nitems, fp);
|
||||||
if (ret == EOF) {
|
if (ret == EOF) {
|
||||||
fprintf(stderr, "[ERROR] failed to write data\n");
|
perror("[ERROR] failed to write data");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +145,7 @@ void mm_err_fread(void *p, size_t size, size_t nitems, FILE *fp)
|
|||||||
int ret;
|
int ret;
|
||||||
ret = fread(p, size, nitems, fp);
|
ret = fread(p, size, nitems, fp);
|
||||||
if (ret == EOF) {
|
if (ret == EOF) {
|
||||||
fprintf(stderr, "[ERROR] failed to read data\n");
|
perror("[ERROR] failed to read data");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,3 +159,4 @@ KRADIX_SORT_INIT(128x, mm128_t, sort_key_128x, 8)
|
|||||||
KRADIX_SORT_INIT(64, uint64_t, sort_key_64, 8)
|
KRADIX_SORT_INIT(64, uint64_t, sort_key_64, 8)
|
||||||
|
|
||||||
KSORT_INIT_GENERIC(uint32_t)
|
KSORT_INIT_GENERIC(uint32_t)
|
||||||
|
KSORT_INIT_GENERIC(uint64_t)
|
||||||
|
|||||||
Executable
+335
@@ -0,0 +1,335 @@
|
|||||||
|
#!/usr/bin/env k8
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
function read_fastx(file, buf)
|
||||||
|
{
|
||||||
|
if (file.readline(buf) < 0) return null;
|
||||||
|
var m, line = buf.toString();
|
||||||
|
if ((m = /^([>@])(\S+)/.exec(line)) == null)
|
||||||
|
throw Error("wrong fastx format");
|
||||||
|
var is_fq = (m[1] == '@');
|
||||||
|
var name = m[2];
|
||||||
|
if (file.readline(buf) < 0)
|
||||||
|
throw Error("missing sequence line");
|
||||||
|
var seq = buf.toString();
|
||||||
|
if (is_fq) { // skip quality
|
||||||
|
file.readline(buf);
|
||||||
|
file.readline(buf);
|
||||||
|
}
|
||||||
|
return [name, seq];
|
||||||
|
}
|
||||||
|
|
||||||
|
function filter_paf(a, opt)
|
||||||
|
{
|
||||||
|
if (a.length == 0) return;
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 0; i < a.length; ++i) {
|
||||||
|
var ai = a[i];
|
||||||
|
if (ai[10] < opt.min_blen) continue;
|
||||||
|
if (ai[9] < ai[10] * opt.min_iden) continue;
|
||||||
|
var clip = [0, 0];
|
||||||
|
if (ai[4] == '+') {
|
||||||
|
clip[0] = ai[2] < ai[7]? ai[2] : ai[7];
|
||||||
|
clip[1] = ai[1] - ai[3] < ai[6] - ai[8]? ai[1] - ai[3] : ai[6] - ai[8];
|
||||||
|
} else {
|
||||||
|
clip[0] = ai[2] < ai[6] - ai[8]? ai[2] : ai[6] - ai[8];
|
||||||
|
clip[1] = ai[1] - ai[3] < ai[7]? ai[1] - ai[3] : ai[7];
|
||||||
|
}
|
||||||
|
if (clip[0] > opt.max_clip_len || clip[1] > opt.max_clip_len) continue;
|
||||||
|
a[k++] = ai;
|
||||||
|
}
|
||||||
|
a.length = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parse_events(t, ev, id, buf)
|
||||||
|
{
|
||||||
|
var re = /(:(\d+))|(([\+\-\*])([a-z]+))/g;
|
||||||
|
var m, cs = null;
|
||||||
|
for (var j = 12; j < t.length; ++j) {
|
||||||
|
if ((m = /^cs:Z:(\S+)/.exec(t[j])) != null) {
|
||||||
|
cs = m[1].toLowerCase();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cs == null) {
|
||||||
|
warn("Warning: no cs tag for read '" + t[0] + "'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var st = t[2], en = t[3];
|
||||||
|
var x = st;
|
||||||
|
while ((m = re.exec(cs)) != null) {
|
||||||
|
var l;
|
||||||
|
if (m[2] != null) { // an identitcal match ":\d+"
|
||||||
|
l = parseInt(m[2]);
|
||||||
|
// [start, end, type, index, changed_base]
|
||||||
|
ev.push([x, x + l, 0, id]);
|
||||||
|
} else {
|
||||||
|
if (m[4] == '*') {
|
||||||
|
l = 1;
|
||||||
|
ev.push([x, x + 1, 1, id, m[5][0]]);
|
||||||
|
} else if (m[4] == '+') {
|
||||||
|
l = m[5].length;
|
||||||
|
ev.push([x, x + l, 2, id]);
|
||||||
|
} else if (m[4] == '-') {
|
||||||
|
l = 0;
|
||||||
|
ev.push([x, x, -1, id, m[5]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x += l;
|
||||||
|
}
|
||||||
|
if (x != en)
|
||||||
|
throw Error("inconsistent cs for read '" + t[0] + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
function find_het_sub(ev, a, opt)
|
||||||
|
{
|
||||||
|
var n = a.length, last0_i = -1, h = [], d = [];
|
||||||
|
for (var i = 0; i < n; ++i) h[i] = [], d[i] = [];
|
||||||
|
for (var i = 0; i < ev.length; ++i) {
|
||||||
|
if (ev[i][2] == 0) {
|
||||||
|
if (last0_i < 0 || ev[i][0] != ev[last0_i][0]) last0_i = i;
|
||||||
|
else if (ev[i][1] > ev[last0_i][1])
|
||||||
|
last0_i = i;
|
||||||
|
} else if (ev[i][2] == 1 && last0_i >= 0 && ev[i][0] < ev[last0_i][1]) {
|
||||||
|
if (ev[last0_i][1] - ev[last0_i][0] >= opt.min_mlen) {
|
||||||
|
if (opt.dbg_ev) print("EV", ev[last0_i].join("\t"), "|", ev[i].join("\t"));
|
||||||
|
var e0 = ev[last0_i], hl = h[e0[3]];
|
||||||
|
if (hl.length == 0 || hl[hl.length-1][0] != e0[0])
|
||||||
|
hl.push([e0[0], e0[1]]);
|
||||||
|
d[ev[i][3]].push([ev[i][0], e0[1] - e0[0]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var b = [];
|
||||||
|
for (var i = 0; i < n; ++i) {
|
||||||
|
var sh = 0, dh = 0;
|
||||||
|
for (var j = 0; j < h[i].length; ++j)
|
||||||
|
sh += h[i][j][1] - h[i][j][0];
|
||||||
|
for (var j = 0; j < d[i].length; ++j)
|
||||||
|
dh += d[i][j][1];
|
||||||
|
// [start, end, index, #consistent, lenConsistent, #conflictive, lenConflictive, identity, mlen]
|
||||||
|
b[i] = [a[i][2], a[i][3], i, h[i].length, sh, d[i].length, dh, a[i][9] / a[i][10], a[i][9]];
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flt_utg_for_ec(b, opt)
|
||||||
|
{
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 0; i < b.length; ++i) {
|
||||||
|
var bi = b[i];
|
||||||
|
if (bi[4] == 0 && bi[6] == 0) b[k++] = bi; // entirely ambiguous
|
||||||
|
else if (bi[6] < (bi[4] + bi[6]) * opt.max_ratio0) b[k++] = bi;
|
||||||
|
}
|
||||||
|
b.length = k;
|
||||||
|
if (b.length == 0) return;
|
||||||
|
// find the longest contiguous segment
|
||||||
|
b.sort(function(x,y) { return x[0]-y[0] });
|
||||||
|
var st = b[0][0], en = b[0][1], max_st = 0, max_en = 0, max_max_en = en;
|
||||||
|
for (var i = 1; i < b.length; ++i) {
|
||||||
|
if (b[i][0] > en) {
|
||||||
|
if (en - st > max_en - max_st)
|
||||||
|
max_st = st, max_en = en;
|
||||||
|
st = b[i][0], en = b[i][1];
|
||||||
|
} else {
|
||||||
|
en = en > b[i][1]? en : b[i][1];
|
||||||
|
}
|
||||||
|
max_max_en = max_max_en > b[i][1]? max_max_en : b[i][1];
|
||||||
|
}
|
||||||
|
if (en - st > max_en - max_st)
|
||||||
|
max_st = st, max_en = en;
|
||||||
|
if (max_max_en != en || st != b[0][0]) {
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 0; i < b.length; ++i)
|
||||||
|
if (b[i][0] < max_en && b[i][1] > max_st)
|
||||||
|
b[k++] = b[i];
|
||||||
|
b.length = k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function flt_utg_for_bin(b, opt) // filter out alignments clearly on the wrong phase
|
||||||
|
{
|
||||||
|
var k = 0;
|
||||||
|
for (var i = 0; i < b.length; ++i) {
|
||||||
|
var bi = b[i];
|
||||||
|
if (bi[4] + bi[6] == 0 || bi[4] >= (bi[4] + bi[6]) * opt.max_ratio0) b[k++] = bi;
|
||||||
|
}
|
||||||
|
b.length = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ec_core(b, n_a, ev, buf, ecb) // error correction
|
||||||
|
{
|
||||||
|
var intv = [];
|
||||||
|
for (var i = 0; i < n_a; ++i)
|
||||||
|
intv[i] = null;
|
||||||
|
intv[b[0][2]] = [b[0][0], b[0][1]];
|
||||||
|
var en = b[0][1];
|
||||||
|
for (var i = 1; i < b.length; ++i) {
|
||||||
|
if (b[i][1] <= en) continue;
|
||||||
|
intv[b[i][2]] = [en, b[i][1]];
|
||||||
|
en = b[i][1];
|
||||||
|
}
|
||||||
|
var k = 0;
|
||||||
|
ecb.capacity = buf.capacity;
|
||||||
|
ecb.length = 0;
|
||||||
|
for (var i = 0; i < ev.length; ++i) {
|
||||||
|
var e = ev[i], I = intv[e[3]];
|
||||||
|
if (I == null) continue;
|
||||||
|
if (e[0] >= I[0] && e[0] < I[1]) { // this is to reduce duplicated events around junctions
|
||||||
|
//print("X", e.join("\t"));
|
||||||
|
if (e[2] == 0) {
|
||||||
|
ecb.length += e[1] - e[0];
|
||||||
|
for (var j = e[0]; j < e[1]; ++j)
|
||||||
|
ecb[k++] = buf[j];
|
||||||
|
} else if (e[2] == 1) {
|
||||||
|
++ecb.length;
|
||||||
|
ecb[k++] = e[4].charCodeAt(0);
|
||||||
|
} else if (e[2] < 0) {
|
||||||
|
ecb.length += e[4].length;
|
||||||
|
for (var j = 0; j < e[4].length; ++j)
|
||||||
|
ecb[k++] = e[4].charCodeAt(j);
|
||||||
|
} // else, skip e[2] == 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ecb.length != k) throw Error("BUG!");
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_paf(a, opt, fp_seq, buf, ecb)
|
||||||
|
{
|
||||||
|
if (a.length == 0) return;
|
||||||
|
var len = a[0][1], name = a[0][0], seq = null;
|
||||||
|
if (len < opt.min_rlen) return;
|
||||||
|
if (fp_seq) {
|
||||||
|
var ret;
|
||||||
|
while ((ret = read_fastx(fp_seq, buf)) != null)
|
||||||
|
if (ret[0] == a[0][0])
|
||||||
|
break;
|
||||||
|
if (ret == null)
|
||||||
|
throw Error("failed to find sequence for read '" + a[0][0] + "'");
|
||||||
|
name = ret[0], seq = ret[1];
|
||||||
|
if (seq.length != len)
|
||||||
|
throw Error("inconsistent length for read '" + name + "'");
|
||||||
|
}
|
||||||
|
filter_paf(a, opt);
|
||||||
|
if (a.length == 0) return;
|
||||||
|
var ev = [];
|
||||||
|
for (var i = 0; i < a.length; ++i)
|
||||||
|
parse_events(a[i], ev, i, buf);
|
||||||
|
ev.sort(function(x,y) { return x[0]!=y[0]? x[0]-y[0] : x[2]-y[2] });
|
||||||
|
if (seq == null) print("SQ", name, a[0][1], a.length);
|
||||||
|
var b = find_het_sub(ev, a, opt);
|
||||||
|
if (opt.ec) flt_utg_for_ec(b, opt);
|
||||||
|
else flt_utg_for_bin(b, opt);
|
||||||
|
if (seq == null) {
|
||||||
|
for (var i = 0; i < b.length; ++i) {
|
||||||
|
var m, ai = a[b[i][2]], score = 0;
|
||||||
|
for (var j = 10; j < ai.length; ++j)
|
||||||
|
if ((m = /^AS:i:(\d+)/.exec(ai[j])) != null)
|
||||||
|
score = m[1];
|
||||||
|
print("TS", b[i][2], b[i][0], b[i][1], ai.slice(5, 9).join("\t"), b[i].slice(3, 7).join("\t"), score);
|
||||||
|
}
|
||||||
|
print("//");
|
||||||
|
} else { // error correction
|
||||||
|
if (b.length == 0) return;
|
||||||
|
buf.set(seq, 0);
|
||||||
|
ec_core(b, a.length, ev, buf, ecb);
|
||||||
|
print(">" + name);
|
||||||
|
print(ecb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(args)
|
||||||
|
{
|
||||||
|
var c, opt = { min_rlen:5000, min_blen:5000, min_iden:0.8, min_mlen:5, max_clip_len:500, max_ratio0:0.25, dbg_ev:false };
|
||||||
|
while ((c = getopt(args, "l:b:d:m:c:r:E")) != null) {
|
||||||
|
if (c == 'l') opt.min_rlen = parseInt(getopt.arg);
|
||||||
|
else if (c == 'b') opt.min_blen = parseInt(getopt.arg);
|
||||||
|
else if (c == 'd') opt.min_iden = parseFloat(getopt.arg);
|
||||||
|
else if (c == 'm') opt.min_slen = parseInt(getopt.arg);
|
||||||
|
else if (c == 'c') opt.max_clip_len = parseInt(getopt.arg);
|
||||||
|
else if (c == 'r') opt.max_ratio0 = parseFloat(getopt.arg);
|
||||||
|
else if (c == 'E') opt.dbg_ev = true;
|
||||||
|
}
|
||||||
|
if (args.length - getopt.ind < 1) {
|
||||||
|
print("Usage: mmphase.js [options] <map-with-cs.paf> [reads.fa]");
|
||||||
|
print("Options:");
|
||||||
|
print(" -l INT min read length [" + opt.min_rlen + "]");
|
||||||
|
print(" -b INT min alignment length [" + opt.min_blen + "]");
|
||||||
|
print(" -d FLOAT min identity [" + opt.min_iden + "]");
|
||||||
|
print(" -s INT min match length [" + opt.min_mlen + "]");
|
||||||
|
print(" -c INT max clip length [" + opt.max_clip_len + "]");
|
||||||
|
print(" -r FLOAT initial ratio for haplotype filtering [" + opt.max_ratio0 + "]");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.ec = args.length - getopt.ind < 2? false : true;
|
||||||
|
if (!opt.ec) {
|
||||||
|
print("CC");
|
||||||
|
print("CC", "SQ qName qLen nHits");
|
||||||
|
print("CC", "TS index qStart qEnd tName tLen tStart tEnd nConsistent lCons nConflictive lConf score");
|
||||||
|
print("CC");
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf = new Bytes(), ecb = new Bytes();
|
||||||
|
var fp_paf = new File(args[getopt.ind]);
|
||||||
|
var fp_seq = args.length - getopt.ind >= 2? new File(args[getopt.ind+1]) : null;
|
||||||
|
var a = [];
|
||||||
|
while (fp_paf.readline(buf) >= 0) {
|
||||||
|
var t = buf.toString().split("\t");
|
||||||
|
if (a.length > 0 && a[0][0] != t[0]) {
|
||||||
|
process_paf(a, opt, fp_seq, buf, ecb);
|
||||||
|
a.length = 0;
|
||||||
|
}
|
||||||
|
for (var i = 1; i <= 3; ++i) t[i] = parseInt(t[i]);
|
||||||
|
if (t[1] < opt.min_rlen) continue;
|
||||||
|
for (var i = 6; i <= 10; ++i) t[i] = parseInt(t[i]);
|
||||||
|
if (t[10] < opt.min_blen) continue;
|
||||||
|
a.push(t);
|
||||||
|
}
|
||||||
|
if (a.length >= 0)
|
||||||
|
process_paf(a, opt, fp_seq, buf, ecb);
|
||||||
|
if (fp_seq) fp_seq.close();
|
||||||
|
fp_paf.close();
|
||||||
|
ecb.destroy();
|
||||||
|
buf.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret = main(arguments)
|
||||||
|
exit(ret)
|
||||||
+971
-70
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "minimap.h"
|
#include "minimap.h"
|
||||||
#include "bseq.h"
|
#include "bseq.h"
|
||||||
|
#include "kseq.h"
|
||||||
|
|
||||||
#define MM_PARENT_UNSET (-1)
|
#define MM_PARENT_UNSET (-1)
|
||||||
#define MM_PARENT_TMP_PRI (-2)
|
#define MM_PARENT_TMP_PRI (-2)
|
||||||
@@ -31,24 +32,17 @@
|
|||||||
#define MALLOC(type, len) ((type*)malloc((len) * sizeof(type)))
|
#define MALLOC(type, len) ((type*)malloc((len) * sizeof(type)))
|
||||||
#define CALLOC(type, len) ((type*)calloc((len), sizeof(type)))
|
#define CALLOC(type, len) ((type*)calloc((len), sizeof(type)))
|
||||||
|
|
||||||
#define REALLOC(ptr, len) ((ptr) = (__typeof__(ptr))realloc((ptr), (len) * sizeof(*(ptr))))
|
|
||||||
|
|
||||||
#define EXPAND(a, m) do { \
|
|
||||||
(m) = (m)? (m) + ((m)>>1) : 16; \
|
|
||||||
REALLOC((a), (m)); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef KSTRING_T
|
typedef struct {
|
||||||
#define KSTRING_T kstring_t
|
uint32_t n;
|
||||||
typedef struct __kstring_t {
|
uint32_t q_pos;
|
||||||
unsigned l, m;
|
uint32_t q_span:31, flt:1;
|
||||||
char *s;
|
uint32_t seg_id:31, is_tandem:1;
|
||||||
} kstring_t;
|
const uint64_t *cr;
|
||||||
#endif
|
} mm_seed_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int n_u, n_a;
|
int n_u, n_a;
|
||||||
@@ -66,30 +60,42 @@ uint32_t ks_ksmall_uint32_t(size_t n, uint32_t arr[], size_t kk);
|
|||||||
|
|
||||||
void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, int is_hpc, mm128_v *p);
|
void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, int is_hpc, mm128_v *p);
|
||||||
|
|
||||||
void mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]);
|
mm_seed_t *mm_collect_matches(void *km, int *_n_m, int qlen, int max_occ, int max_max_occ, int dist, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos);
|
||||||
void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int opt_flag);
|
|
||||||
|
double mm_event_identity(const mm_reg1_t *r);
|
||||||
|
int mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]);
|
||||||
|
void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int64_t opt_flag);
|
||||||
|
void mm_write_paf3(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int64_t opt_flag, int rep_len);
|
||||||
void mm_write_sam(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int n_regs, const mm_reg1_t *regs);
|
void mm_write_sam(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int n_regs, const mm_reg1_t *regs);
|
||||||
void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regs, const mm_reg1_t *const* regs, void *km, int opt_flag);
|
void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regs, const mm_reg1_t *const* regs, void *km, int64_t opt_flag);
|
||||||
|
void mm_write_sam3(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int seg_idx, int reg_idx, int n_seg, const int *n_regss, const mm_reg1_t *const* regss, void *km, int64_t opt_flag, int rep_len);
|
||||||
|
|
||||||
void mm_idxopt_init(mm_idxopt_t *opt);
|
void mm_idxopt_init(mm_idxopt_t *opt);
|
||||||
const uint64_t *mm_idx_get(const mm_idx_t *mi, uint64_t minier, int *n);
|
const uint64_t *mm_idx_get(const mm_idx_t *mi, uint64_t minier, int *n);
|
||||||
int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f);
|
int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f);
|
||||||
int mm_idx_getseq2(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq, int8_t *b);
|
int mm_idx_getseq2(const mm_idx_t *mi, int is_rev, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq);
|
||||||
mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int min_cnt, int min_sc, int is_cdna, int n_segs, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km);
|
|
||||||
mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a);
|
mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a);
|
||||||
|
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a, int is_qstrand);
|
||||||
|
|
||||||
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a);
|
mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int max_iter, int min_cnt, int min_sc, float gap_scale,
|
||||||
void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a);
|
int is_cdna, int n_segs, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km);
|
||||||
|
mm128_t *mg_lchain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int max_iter, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
|
||||||
|
int is_cdna, int n_segs, int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km);
|
||||||
|
mm128_t *mg_lchain_rmq(int max_dist, int max_dist_inner, int bw, int max_chn_skip, int cap_rmq_size, int min_cnt, int min_sc, float chn_pen_gap, float chn_pen_skip,
|
||||||
|
int64_t n, mm128_t *a, int *n_u_, uint64_t **_u, void *km);
|
||||||
|
|
||||||
|
void mm_mark_alt(const mm_idx_t *mi, int n, mm_reg1_t *r);
|
||||||
|
void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a, int is_qstrand);
|
||||||
void mm_sync_regs(void *km, int n_regs, mm_reg1_t *regs);
|
void mm_sync_regs(void *km, int n_regs, mm_reg1_t *regs);
|
||||||
int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a);
|
int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a);
|
||||||
int mm_set_sam_pri(int n, mm_reg1_t *r);
|
int mm_set_sam_pri(int n, mm_reg1_t *r);
|
||||||
void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level);
|
void mm_set_parent(void *km, float mask_level, int mask_len, int n, mm_reg1_t *r, int sub_diff, int hard_mask_level, float alt_diff_frac);
|
||||||
void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_, mm_reg1_t *r);
|
void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_, mm_reg1_t *r);
|
||||||
void mm_select_sub_multi(void *km, float pri_ratio, float pri1, float pri2, int max_gap_ref, int min_diff, int best_n, int n_segs, const int *qlens, int *n_, mm_reg1_t *r);
|
void mm_select_sub_multi(void *km, float pri_ratio, float pri1, float pri2, int max_gap_ref, int min_diff, int best_n, int n_segs, const int *qlens, int *n_, mm_reg1_t *r);
|
||||||
void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs);
|
void mm_filter_regs(const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs);
|
||||||
void mm_join_long(void *km, const mm_mapopt_t *opt, int qlen, int *n_regs, mm_reg1_t *regs, mm128_t *a);
|
void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r, float alt_diff_frac);
|
||||||
void mm_hit_sort(void *km, int *n_regs, mm_reg1_t *r);
|
|
||||||
void mm_set_mapq(void *km, int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr);
|
void mm_set_mapq(void *km, int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr);
|
||||||
|
void mm_update_dp_max(int qlen, int n_regs, mm_reg1_t *regs, float frac, int a, int b);
|
||||||
|
|
||||||
void mm_est_err(const mm_idx_t *mi, int qlen, int n_regs, mm_reg1_t *regs, const mm128_t *a, int32_t n, const uint64_t *mini_pos);
|
void mm_est_err(const mm_idx_t *mi, int qlen, int n_regs, mm_reg1_t *regs, const mm128_t *a, int32_t n, const uint64_t *mini_pos);
|
||||||
|
|
||||||
@@ -106,6 +112,16 @@ void mm_err_puts(const char *str);
|
|||||||
void mm_err_fwrite(const void *p, size_t size, size_t nitems, FILE *fp);
|
void mm_err_fwrite(const void *p, size_t size, size_t nitems, FILE *fp);
|
||||||
void mm_err_fread(void *p, size_t size, size_t nitems, FILE *fp);
|
void mm_err_fread(void *p, size_t size, size_t nitems, FILE *fp);
|
||||||
|
|
||||||
|
static inline float mg_log2(float x) // NB: this doesn't work when x<2
|
||||||
|
{
|
||||||
|
union { float f; uint32_t i; } z = { x };
|
||||||
|
float log_2 = ((z.i >> 23) & 255) - 128;
|
||||||
|
z.i &= ~(255 << 23);
|
||||||
|
z.i += 127 << 23;
|
||||||
|
log_2 += (-0.34484843f * z.f + 2.02466578f) * z.f - 0.67487759f;
|
||||||
|
return log_2;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
|
|
||||||
void mm_idxopt_init(mm_idxopt_t *opt)
|
void mm_idxopt_init(mm_idxopt_t *opt)
|
||||||
@@ -15,23 +16,31 @@ void mm_mapopt_init(mm_mapopt_t *opt)
|
|||||||
memset(opt, 0, sizeof(mm_mapopt_t));
|
memset(opt, 0, sizeof(mm_mapopt_t));
|
||||||
opt->seed = 11;
|
opt->seed = 11;
|
||||||
opt->mid_occ_frac = 2e-4f;
|
opt->mid_occ_frac = 2e-4f;
|
||||||
|
opt->min_mid_occ = 10;
|
||||||
|
opt->max_mid_occ = 1000000;
|
||||||
opt->sdust_thres = 0; // no SDUST masking
|
opt->sdust_thres = 0; // no SDUST masking
|
||||||
|
|
||||||
opt->min_cnt = 3;
|
opt->min_cnt = 3;
|
||||||
opt->min_chain_score = 40;
|
opt->min_chain_score = 40;
|
||||||
opt->bw = 500;
|
opt->bw = 500, opt->bw_long = 20000;
|
||||||
opt->max_gap = 5000;
|
opt->max_gap = 5000;
|
||||||
opt->max_gap_ref = -1;
|
opt->max_gap_ref = -1;
|
||||||
opt->max_chain_skip = 25;
|
opt->max_chain_skip = 25;
|
||||||
|
opt->max_chain_iter = 5000;
|
||||||
|
opt->rmq_inner_dist = 1000;
|
||||||
|
opt->rmq_size_cap = 100000;
|
||||||
|
opt->rmq_rescue_size = 1000;
|
||||||
|
opt->rmq_rescue_ratio = 0.1f;
|
||||||
|
opt->chain_gap_scale = 0.8f;
|
||||||
|
opt->max_max_occ = 4095;
|
||||||
|
opt->occ_dist = 500;
|
||||||
|
|
||||||
opt->mask_level = 0.5f;
|
opt->mask_level = 0.5f;
|
||||||
|
opt->mask_len = INT_MAX;
|
||||||
opt->pri_ratio = 0.8f;
|
opt->pri_ratio = 0.8f;
|
||||||
opt->best_n = 5;
|
opt->best_n = 5;
|
||||||
|
|
||||||
opt->max_join_long = 20000;
|
opt->alt_drop = 0.15f;
|
||||||
opt->max_join_short = 2000;
|
|
||||||
opt->min_join_flank_sc = 1000;
|
|
||||||
opt->min_join_flank_ratio = 0.5f;
|
|
||||||
|
|
||||||
opt->a = 2, opt->b = 4, opt->q = 4, opt->e = 2, opt->q2 = 24, opt->e2 = 1;
|
opt->a = 2, opt->b = 4, opt->q = 4, opt->e = 2, opt->q2 = 24, opt->e2 = 1;
|
||||||
opt->sc_ambi = 1;
|
opt->sc_ambi = 1;
|
||||||
@@ -42,6 +51,10 @@ void mm_mapopt_init(mm_mapopt_t *opt)
|
|||||||
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
|
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
|
||||||
opt->max_clip_ratio = 1.0f;
|
opt->max_clip_ratio = 1.0f;
|
||||||
opt->mini_batch_size = 500000000;
|
opt->mini_batch_size = 500000000;
|
||||||
|
opt->max_sw_mat = 100000000;
|
||||||
|
|
||||||
|
opt->rank_min_len = 500;
|
||||||
|
opt->rank_frac = 0.9f;
|
||||||
|
|
||||||
opt->pe_ori = 0; // FF
|
opt->pe_ori = 0; // FF
|
||||||
opt->pe_bonus = 33;
|
opt->pe_bonus = 33;
|
||||||
@@ -51,10 +64,13 @@ 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))
|
if ((opt->flag & MM_F_SPLICE_FOR) || (opt->flag & MM_F_SPLICE_REV))
|
||||||
opt->flag |= MM_F_SPLICE;
|
opt->flag |= MM_F_SPLICE;
|
||||||
if (opt->mid_occ <= 0)
|
if (opt->mid_occ <= 0) {
|
||||||
opt->mid_occ = mm_idx_cal_max_occ(mi, opt->mid_occ_frac);
|
opt->mid_occ = mm_idx_cal_max_occ(mi, opt->mid_occ_frac);
|
||||||
if (opt->mid_occ < opt->min_mid_occ)
|
if (opt->mid_occ < opt->min_mid_occ)
|
||||||
opt->mid_occ = opt->min_mid_occ;
|
opt->mid_occ = opt->min_mid_occ;
|
||||||
|
if (opt->max_mid_occ > opt->min_mid_occ && opt->mid_occ > opt->max_mid_occ)
|
||||||
|
opt->mid_occ = opt->max_mid_occ;
|
||||||
|
}
|
||||||
if (mm_verbose >= 3)
|
if (mm_verbose >= 3)
|
||||||
fprintf(stderr, "[M::%s::%.3f*%.2f] mid_occ = %d\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), opt->mid_occ);
|
fprintf(stderr, "[M::%s::%.3f*%.2f] mid_occ = %d\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), opt->mid_occ);
|
||||||
}
|
}
|
||||||
@@ -62,7 +78,7 @@ void mm_mapopt_update(mm_mapopt_t *opt, const mm_idx_t *mi)
|
|||||||
void mm_mapopt_max_intron_len(mm_mapopt_t *opt, int max_intron_len)
|
void mm_mapopt_max_intron_len(mm_mapopt_t *opt, int max_intron_len)
|
||||||
{
|
{
|
||||||
if ((opt->flag & MM_F_SPLICE) && max_intron_len > 0)
|
if ((opt->flag & MM_F_SPLICE) && max_intron_len > 0)
|
||||||
opt->max_gap_ref = opt->bw = max_intron_len;
|
opt->max_gap_ref = opt->bw = opt->bw_long = max_intron_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -70,37 +86,44 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
|||||||
if (preset == 0) {
|
if (preset == 0) {
|
||||||
mm_idxopt_init(io);
|
mm_idxopt_init(io);
|
||||||
mm_mapopt_init(mo);
|
mm_mapopt_init(mo);
|
||||||
|
} else if (strcmp(preset, "map-ont") == 0) { // this is the same as the default
|
||||||
} else if (strcmp(preset, "ava-ont") == 0) {
|
} else if (strcmp(preset, "ava-ont") == 0) {
|
||||||
io->flag = 0, io->k = 15, io->w = 5;
|
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->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;
|
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_chain_skip = 25;
|
||||||
mo->bw = 2000;
|
mo->bw = mo->bw_long = 2000;
|
||||||
|
mo->occ_dist = 0;
|
||||||
|
} else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
|
||||||
|
io->flag |= MM_I_HPC, io->k = 19;
|
||||||
} else if (strcmp(preset, "ava-pb") == 0) {
|
} else if (strcmp(preset, "ava-pb") == 0) {
|
||||||
io->flag |= MM_I_HPC, io->k = 19, io->w = 5;
|
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->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;
|
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_chain_skip = 25;
|
||||||
} else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
|
mo->bw_long = mo->bw;
|
||||||
io->flag |= MM_I_HPC, io->k = 19;
|
mo->occ_dist = 0;
|
||||||
} else if (strcmp(preset, "map-ont") == 0) {
|
} else if (strcmp(preset, "map-hifi") == 0 || strcmp(preset, "map-ccs") == 0) {
|
||||||
io->flag = 0, io->k = 15;
|
|
||||||
} else if (strcmp(preset, "asm5") == 0) {
|
|
||||||
io->flag = 0, io->k = 19, io->w = 19;
|
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 = mo->zdrop_inv = 200;
|
mo->max_gap = 10000;
|
||||||
mo->min_mid_occ = 100;
|
mo->a = 1, mo->b = 4, mo->q = 6, mo->q2 = 26, mo->e = 2, mo->e2 = 1;
|
||||||
|
mo->occ_dist = 500;
|
||||||
|
mo->min_mid_occ = 50, mo->max_mid_occ = 500;
|
||||||
mo->min_dp_max = 200;
|
mo->min_dp_max = 200;
|
||||||
mo->best_n = 50;
|
} else if (strncmp(preset, "asm", 3) == 0) {
|
||||||
} else if (strcmp(preset, "asm10") == 0) {
|
|
||||||
io->flag = 0, io->k = 19, io->w = 19;
|
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 = mo->zdrop_inv = 200;
|
mo->bw = mo->bw_long = 100000;
|
||||||
mo->min_mid_occ = 100;
|
mo->max_gap = 10000;
|
||||||
mo->min_dp_max = 200;
|
mo->flag |= MM_F_RMQ;
|
||||||
mo->best_n = 50;
|
mo->min_mid_occ = 50, mo->max_mid_occ = 500;
|
||||||
} else if (strcmp(preset, "asm20") == 0) {
|
|
||||||
io->flag = 0, io->k = 19, io->w = 10;
|
|
||||||
mo->a = 1, mo->b = 4, mo->q = 6, mo->q2 = 26, mo->e = 2, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
|
|
||||||
mo->min_mid_occ = 100;
|
|
||||||
mo->min_dp_max = 200;
|
mo->min_dp_max = 200;
|
||||||
mo->best_n = 50;
|
mo->best_n = 50;
|
||||||
|
if (strcmp(preset, "asm5") == 0) {
|
||||||
|
mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
|
||||||
|
} else if (strcmp(preset, "asm10") == 0) {
|
||||||
|
mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
|
||||||
|
} else if (strcmp(preset, "asm20") == 0) {
|
||||||
|
mo->a = 1, mo->b = 4, mo->q = 6, mo->q2 = 26, mo->e = 2, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
|
||||||
|
io->w = 10;
|
||||||
|
} else return -1;
|
||||||
} else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) {
|
} else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) {
|
||||||
io->flag = 0, io->k = 21, io->w = 11;
|
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->flag |= MM_F_SR | MM_F_FRAG_MODE | MM_F_NO_PRINT_2ND | MM_F_2_IO_THREADS | MM_F_HEAP_SORT;
|
||||||
@@ -110,7 +133,7 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
|||||||
mo->end_bonus = 10;
|
mo->end_bonus = 10;
|
||||||
mo->max_frag_len = 800;
|
mo->max_frag_len = 800;
|
||||||
mo->max_gap = 100;
|
mo->max_gap = 100;
|
||||||
mo->bw = 100;
|
mo->bw = mo->bw_long = 100;
|
||||||
mo->pri_ratio = 0.5f;
|
mo->pri_ratio = 0.5f;
|
||||||
mo->min_cnt = 2;
|
mo->min_cnt = 2;
|
||||||
mo->min_chain_score = 25;
|
mo->min_chain_score = 25;
|
||||||
@@ -119,19 +142,33 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
|||||||
mo->mid_occ = 1000;
|
mo->mid_occ = 1000;
|
||||||
mo->max_occ = 5000;
|
mo->max_occ = 5000;
|
||||||
mo->mini_batch_size = 50000000;
|
mo->mini_batch_size = 50000000;
|
||||||
} else if (strcmp(preset, "splice") == 0 || strcmp(preset, "cdna") == 0) {
|
} else if (strncmp(preset, "splice", 6) == 0 || strcmp(preset, "cdna") == 0) {
|
||||||
io->flag = 0, io->k = 15, io->w = 5;
|
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->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->max_sw_mat = 0;
|
||||||
|
mo->max_gap = 2000, mo->max_gap_ref = mo->bw = mo->bw_long = 200000;
|
||||||
mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0;
|
mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0;
|
||||||
mo->noncan = 9;
|
mo->noncan = 9;
|
||||||
|
mo->junc_bonus = 9;
|
||||||
mo->zdrop = 200, mo->zdrop_inv = 100; // because mo->a is halved
|
mo->zdrop = 200, mo->zdrop_inv = 100; // because mo->a is halved
|
||||||
|
if (strcmp(preset, "splice:hq") == 0)
|
||||||
|
mo->junc_bonus = 5, mo->b = 4, mo->q = 6, mo->q2 = 24;
|
||||||
} else return -1;
|
} else return -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
|
int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
|
||||||
{
|
{
|
||||||
|
if (mo->bw > mo->bw_long) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m with '-rNUM1,NUM2', NUM1 (%d) can't be larger than NUM2 (%d)\033[0m\n", mo->bw, mo->bw_long);
|
||||||
|
return -8;
|
||||||
|
}
|
||||||
|
if ((mo->flag & MM_F_RMQ) && (mo->flag & (MM_F_SR|MM_F_SPLICE))) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m --rmq doesn't work with --sr or --splice\033[0m\n");
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
if (mo->split_prefix && (mo->flag & (MM_F_OUT_CS|MM_F_OUT_MD))) {
|
if (mo->split_prefix && (mo->flag & (MM_F_OUT_CS|MM_F_OUT_MD))) {
|
||||||
if (mm_verbose >= 1)
|
if (mm_verbose >= 1)
|
||||||
fprintf(stderr, "[ERROR]\033[1;31m --cs or --MD doesn't work with --split-prefix\033[0m\n");
|
fprintf(stderr, "[ERROR]\033[1;31m --cs or --MD doesn't work with --split-prefix\033[0m\n");
|
||||||
@@ -159,6 +196,11 @@ int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
|
|||||||
fprintf(stderr, "[ERROR]\033[1;31m --for-only and --rev-only can't be applied at the same time\033[0m\n");
|
fprintf(stderr, "[ERROR]\033[1;31m --for-only and --rev-only can't be applied at the same time\033[0m\n");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
if (mo->e <= 0 || mo->q <= 0) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m -O and -E must be positive\033[0m\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if ((mo->q != mo->q2 || mo->e != mo->e2) && !(mo->e > mo->e2 && mo->q + mo->e < mo->q2 + mo->e2)) {
|
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)
|
if (mm_verbose >= 1)
|
||||||
fprintf(stderr, "[ERROR]\033[1;31m dual gap penalties violating E1>E2 and O1+E1<O2+E2\033[0m\n");
|
fprintf(stderr, "[ERROR]\033[1;31m dual gap penalties violating E1>E2 and O1+E1<O2+E2\033[0m\n");
|
||||||
@@ -179,5 +221,10 @@ int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
|
|||||||
fprintf(stderr, "[ERROR]\033[1;31m -X/-P and --secondary=no can't be applied at the same time\033[0m\n");
|
fprintf(stderr, "[ERROR]\033[1;31m -X/-P and --secondary=no can't be applied at the same time\033[0m\n");
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
if ((mo->flag & MM_F_QSTRAND) && ((mo->flag & (MM_F_OUT_SAM|MM_F_SPLICE|MM_F_FRAG_MODE)) || (io->flag & MM_I_HPC))) {
|
||||||
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m --qstrand doesn't work with -a, -H, --frag or --splice\033[0m\n");
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ void mm_set_pe_thru(const int *qlens, int *n_regs, mm_reg1_t **regs)
|
|||||||
if (n_pri[0] == 1 && n_pri[1] == 1) {
|
if (n_pri[0] == 1 && n_pri[1] == 1) {
|
||||||
mm_reg1_t *p = ®s[0][pri[0]];
|
mm_reg1_t *p = ®s[0][pri[0]];
|
||||||
mm_reg1_t *q = ®s[1][pri[1]];
|
mm_reg1_t *q = ®s[1][pri[1]];
|
||||||
if (p->rid == q->rid && p->rev == q->rev && abs(p->rs - q->rs) < 3 && abs(p->re - p->re) < 3
|
if (p->rid == q->rid && p->rev == q->rev && abs(p->rs - q->rs) < 3 && abs(p->re - q->re) < 3
|
||||||
&& ((p->qs == 0 && qlens[1] - q->qe == 0) || (q->qs == 0 && qlens[0] - p->qe == 0)))
|
&& ((p->qs == 0 && qlens[1] - q->qe == 0) || (q->qs == 0 && qlens[0] - p->qe == 0)))
|
||||||
{
|
{
|
||||||
p->pe_thru = q->pe_thru = 1;
|
p->pe_thru = q->pe_thru = 1;
|
||||||
|
|||||||
+7
-1
@@ -114,6 +114,12 @@ This method retrieves a (sub)sequence from the index and returns it as a Python
|
|||||||
string. :code:`None` is returned if :code:`name` is not present in the index or
|
string. :code:`None` is returned if :code:`name` is not present in the index or
|
||||||
the start/end coordinates are invalid.
|
the start/end coordinates are invalid.
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
mappy.Aligner.seq_names
|
||||||
|
|
||||||
|
This property gives the array of sequence names in the index.
|
||||||
|
|
||||||
Class mappy.Alignment
|
Class mappy.Alignment
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -138,7 +144,7 @@ properties:
|
|||||||
* **mlen**: length of the matching bases in the alignment, excluding ambiguous
|
* **mlen**: length of the matching bases in the alignment, excluding ambiguous
|
||||||
base matches.
|
base matches.
|
||||||
|
|
||||||
* **NM**: number of mismatches, gaps and ambiguous poistions in the alignment
|
* **NM**: number of mismatches, gaps and ambiguous positions in the alignment
|
||||||
|
|
||||||
* **trans_strand**: transcript strand. +1 if on the forward strand; -1 if on the
|
* **trans_strand**: transcript strand. +1 if on the forward strand; -1 if on the
|
||||||
reverse strand; 0 if unknown
|
reverse strand; 0 if unknown
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ typedef struct {
|
|||||||
uint32_t *cigar32;
|
uint32_t *cigar32;
|
||||||
} mm_hitpy_t;
|
} mm_hitpy_t;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int32_t n, m;
|
|
||||||
mm_idx_bed_t *r;
|
|
||||||
} mm_bedpy_t;
|
|
||||||
|
|
||||||
static inline void mm_reg2hitpy(const mm_idx_t *mi, mm_reg1_t *r, mm_hitpy_t *h)
|
static inline void mm_reg2hitpy(const mm_idx_t *mi, mm_reg1_t *r, mm_hitpy_t *h)
|
||||||
{
|
{
|
||||||
h->ctg = mi->seq[r->rid].name;
|
h->ctg = mi->seq[r->rid].name;
|
||||||
@@ -154,33 +149,4 @@ static mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const
|
|||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mm_bedpy_t *mappy_bed_new(void)
|
|
||||||
{
|
|
||||||
return (mm_bedpy_t*)calloc(1, sizeof(mm_bedpy_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mappy_bed_add(mm_bedpy_t *bed, mm_idx_t *mi, const char *name, uint32_t st, uint32_t en)
|
|
||||||
{
|
|
||||||
mm_idx_bed_t *b;
|
|
||||||
int id;
|
|
||||||
if (mi->h == 0) mm_idx_index_name(mi);
|
|
||||||
if (bed->n == bed->m) {
|
|
||||||
bed->m = bed->m? bed->m + (bed->m>>1) : 16;
|
|
||||||
bed->r = (mm_idx_bed_t*)realloc(bed->r, sizeof(mm_idx_bed_t) * bed->m);
|
|
||||||
}
|
|
||||||
id = mm_idx_name2id(mi, name);
|
|
||||||
if (id < 0 || st >= en) return -1;
|
|
||||||
if (en > mi->seq[id].len) en = mi->seq[id].len;
|
|
||||||
b = &bed->r[bed->n++];
|
|
||||||
b->x = (uint64_t)id << 32 | st;
|
|
||||||
b->end = en, b->idx = -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mappy_bed_finalize(mm_bedpy_t *bed, mm_idx_t *mi)
|
|
||||||
{
|
|
||||||
mm_idx_bed_attach(mi, bed->n, bed->r); // bed->r is now owned by mi and will be deallocated with it
|
|
||||||
free(bed);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+26
-21
@@ -6,40 +6,58 @@ cdef extern from "minimap.h":
|
|||||||
#
|
#
|
||||||
ctypedef struct mm_idxopt_t:
|
ctypedef struct mm_idxopt_t:
|
||||||
short k, w, flag, bucket_bits
|
short k, w, flag, bucket_bits
|
||||||
int mini_batch_size
|
int64_t mini_batch_size
|
||||||
uint64_t batch_size
|
uint64_t batch_size
|
||||||
|
|
||||||
ctypedef struct mm_mapopt_t:
|
ctypedef struct mm_mapopt_t:
|
||||||
|
int64_t flag
|
||||||
int seed
|
int seed
|
||||||
int sdust_thres
|
int sdust_thres
|
||||||
int flag
|
|
||||||
int bw
|
int max_qlen
|
||||||
|
|
||||||
|
int bw, bw_long
|
||||||
int max_gap, max_gap_ref
|
int max_gap, max_gap_ref
|
||||||
int max_frag_len
|
int max_frag_len
|
||||||
int max_chain_skip
|
int max_chain_skip, max_chain_iter
|
||||||
int min_cnt
|
int min_cnt
|
||||||
int min_chain_score
|
int min_chain_score
|
||||||
|
float chain_gap_scale
|
||||||
|
int rmq_size_cap, rmq_inner_dist
|
||||||
|
int rmq_rescue_size
|
||||||
|
float rmq_rescue_ratio
|
||||||
|
|
||||||
float mask_level
|
float mask_level
|
||||||
|
int mask_len
|
||||||
float pri_ratio
|
float pri_ratio
|
||||||
int best_n
|
int best_n
|
||||||
int max_join_long, max_join_short
|
|
||||||
int min_join_flank_sc
|
float alt_drop
|
||||||
float min_join_flank_ratio;
|
|
||||||
int a, b, q, e, q2, e2
|
int a, b, q, e, q2, e2
|
||||||
int sc_ambi
|
int sc_ambi
|
||||||
int noncan
|
int noncan
|
||||||
|
int junc_bonus
|
||||||
int zdrop, zdrop_inv
|
int zdrop, zdrop_inv
|
||||||
int end_bonus
|
int end_bonus
|
||||||
int min_dp_max
|
int min_dp_max
|
||||||
int min_ksw_len
|
int min_ksw_len
|
||||||
int anchor_ext_len, anchor_ext_shift
|
int anchor_ext_len, anchor_ext_shift
|
||||||
float max_clip_ratio
|
float max_clip_ratio
|
||||||
|
|
||||||
|
int rank_min_len
|
||||||
|
float rank_frac
|
||||||
|
|
||||||
int pe_ori, pe_bonus
|
int pe_ori, pe_bonus
|
||||||
|
|
||||||
float mid_occ_frac
|
float mid_occ_frac
|
||||||
int32_t min_mid_occ
|
int32_t min_mid_occ
|
||||||
int32_t mid_occ
|
int32_t mid_occ
|
||||||
int32_t max_occ
|
int32_t max_occ
|
||||||
int mini_batch_size
|
int64_t mini_batch_size
|
||||||
|
int64_t max_sw_mat
|
||||||
|
int64_t cap_kalloc
|
||||||
|
|
||||||
const char *split_prefix
|
const char *split_prefix
|
||||||
|
|
||||||
int mm_set_opt(char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
int mm_set_opt(char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
|
||||||
@@ -53,10 +71,6 @@ cdef extern from "minimap.h":
|
|||||||
uint64_t offset
|
uint64_t offset
|
||||||
uint32_t len
|
uint32_t len
|
||||||
|
|
||||||
ctypedef struct mm_idx_bed_t:
|
|
||||||
uint64_t x
|
|
||||||
int32_t end, idx
|
|
||||||
|
|
||||||
ctypedef struct mm_idx_bucket_t:
|
ctypedef struct mm_idx_bucket_t:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -66,7 +80,6 @@ cdef extern from "minimap.h":
|
|||||||
mm_idx_seq_t *seq
|
mm_idx_seq_t *seq
|
||||||
uint32_t *S
|
uint32_t *S
|
||||||
mm_idx_bucket_t *B
|
mm_idx_bucket_t *B
|
||||||
mm_idx_bed_t *R
|
|
||||||
void *km
|
void *km
|
||||||
void *h
|
void *h
|
||||||
|
|
||||||
@@ -117,14 +130,6 @@ cdef extern from "cmappy.h":
|
|||||||
char *mappy_fetch_seq(const mm_idx_t *mi, const char *name, int st, int en, int *l)
|
char *mappy_fetch_seq(const mm_idx_t *mi, const char *name, int st, int en, int *l)
|
||||||
mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const char *seq, int l)
|
mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const char *seq, int l)
|
||||||
|
|
||||||
ctypedef struct mm_bedpy_t:
|
|
||||||
int32_t n, m
|
|
||||||
mm_idx_bed_t *r
|
|
||||||
|
|
||||||
mm_bedpy_t *mappy_bed_new()
|
|
||||||
int mappy_bed_add(mm_bedpy_t *bed, mm_idx_t *mi, const char *name, uint32_t st, uint32_t en)
|
|
||||||
void mappy_bed_finalize(mm_bedpy_t *bed, mm_idx_t *mi)
|
|
||||||
|
|
||||||
ctypedef struct kstring_t:
|
ctypedef struct kstring_t:
|
||||||
unsigned l, m
|
unsigned l, m
|
||||||
char *s
|
char *s
|
||||||
|
|||||||
+44
-31
@@ -3,7 +3,7 @@ from libc.stdlib cimport free
|
|||||||
cimport cmappy
|
cimport cmappy
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
__version__ = '2.13'
|
__version__ = '2.22'
|
||||||
|
|
||||||
cmappy.mm_reset_timer()
|
cmappy.mm_reset_timer()
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ cdef class Alignment:
|
|||||||
|
|
||||||
@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]) + 'MIDNSHP=XB'[x[1]], self._cigar))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self._strand > 0: strand = '+'
|
if self._strand > 0: strand = '+'
|
||||||
@@ -112,7 +112,8 @@ cdef class Aligner:
|
|||||||
cdef cmappy.mm_idxopt_t idx_opt
|
cdef cmappy.mm_idxopt_t idx_opt
|
||||||
cdef cmappy.mm_mapopt_t map_opt
|
cdef cmappy.mm_mapopt_t map_opt
|
||||||
|
|
||||||
def __cinit__(self, fn_idx_in=None, preset=None, k=None, w=None, min_cnt=None, min_chain_score=None, min_dp_score=None, bw=None, best_n=None, n_threads=3, fn_idx_out=None, max_frag_len=None, extra_flags=None, seq=None, scoring=None, bed=None):
|
def __cinit__(self, fn_idx_in=None, preset=None, k=None, w=None, min_cnt=None, min_chain_score=None, min_dp_score=None, bw=None, best_n=None, n_threads=3, fn_idx_out=None, max_frag_len=None, extra_flags=None, seq=None, scoring=None):
|
||||||
|
self._idx = NULL
|
||||||
cmappy.mm_set_opt(NULL, &self.idx_opt, &self.map_opt) # set the default options
|
cmappy.mm_set_opt(NULL, &self.idx_opt, &self.map_opt) # set the default options
|
||||||
if preset is not None:
|
if preset is not None:
|
||||||
cmappy.mm_set_opt(str.encode(preset), &self.idx_opt, &self.map_opt) # apply preset
|
cmappy.mm_set_opt(str.encode(preset), &self.idx_opt, &self.map_opt) # apply preset
|
||||||
@@ -137,13 +138,12 @@ cdef class Aligner:
|
|||||||
self.map_opt.sc_ambi = scoring[6]
|
self.map_opt.sc_ambi = scoring[6]
|
||||||
|
|
||||||
cdef cmappy.mm_idx_reader_t *r;
|
cdef cmappy.mm_idx_reader_t *r;
|
||||||
cdef cmappy.mm_bedpy_t *bed_agg;
|
|
||||||
|
|
||||||
if seq is None:
|
if seq is None:
|
||||||
if fn_idx_out is None:
|
if fn_idx_out is None:
|
||||||
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, NULL)
|
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, NULL)
|
||||||
else:
|
else:
|
||||||
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, fn_idx_out)
|
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, str.encode(fn_idx_out))
|
||||||
if r is not NULL:
|
if r is not NULL:
|
||||||
self._idx = cmappy.mm_idx_reader_read(r, n_threads) # NB: ONLY read the first part
|
self._idx = cmappy.mm_idx_reader_read(r, n_threads) # NB: ONLY read the first part
|
||||||
cmappy.mm_idx_reader_close(r)
|
cmappy.mm_idx_reader_close(r)
|
||||||
@@ -154,14 +154,6 @@ cdef class Aligner:
|
|||||||
cmappy.mm_mapopt_update(&self.map_opt, self._idx)
|
cmappy.mm_mapopt_update(&self.map_opt, self._idx)
|
||||||
self.map_opt.mid_occ = 1000 # don't filter high-occ seeds
|
self.map_opt.mid_occ = 1000 # don't filter high-occ seeds
|
||||||
|
|
||||||
if bed is not None:
|
|
||||||
bed_agg = cmappy.mappy_bed_new()
|
|
||||||
for b in bed:
|
|
||||||
if len(b) < 3: en = int(b[1]) + 1
|
|
||||||
else: en = int(b[2])
|
|
||||||
cmappy.mappy_bed_add(bed_agg, self._idx, str.encode(b[0]), int(b[1]), en)
|
|
||||||
cmappy.mappy_bed_finalize(bed_agg, self._idx)
|
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
if self._idx is not NULL:
|
if self._idx is not NULL:
|
||||||
cmappy.mm_idx_destroy(self._idx)
|
cmappy.mm_idx_destroy(self._idx)
|
||||||
@@ -179,6 +171,7 @@ cdef class Aligner:
|
|||||||
cdef void *km
|
cdef void *km
|
||||||
cdef cmappy.mm_mapopt_t map_opt
|
cdef cmappy.mm_mapopt_t map_opt
|
||||||
|
|
||||||
|
if self._idx == NULL: return
|
||||||
map_opt = self.map_opt
|
map_opt = self.map_opt
|
||||||
if max_frag_len is not None: map_opt.max_frag_len = max_frag_len
|
if max_frag_len is not None: map_opt.max_frag_len = max_frag_len
|
||||||
if extra_flags is not None: map_opt.flag |= extra_flags
|
if extra_flags is not None: map_opt.flag |= extra_flags
|
||||||
@@ -195,27 +188,36 @@ cdef class Aligner:
|
|||||||
_seq2 = seq2 if isinstance(seq2, bytes) else seq2.encode()
|
_seq2 = seq2 if isinstance(seq2, bytes) else seq2.encode()
|
||||||
regs = cmappy.mm_map_aux(self._idx, _seq, _seq2, &n_regs, b._b, &map_opt)
|
regs = cmappy.mm_map_aux(self._idx, _seq, _seq2, &n_regs, b._b, &map_opt)
|
||||||
|
|
||||||
for i in range(n_regs):
|
try:
|
||||||
cmappy.mm_reg2hitpy(self._idx, ®s[i], &h)
|
i = 0
|
||||||
cigar, _cs, _MD = [], '', ''
|
while i < n_regs:
|
||||||
for k in range(h.n_cigar32): # convert the 32-bit CIGAR encoding to Python array
|
cmappy.mm_reg2hitpy(self._idx, ®s[i], &h)
|
||||||
c = h.cigar32[k]
|
cigar, _cs, _MD = [], '', ''
|
||||||
cigar.append([c>>4, c&0xf])
|
for k in range(h.n_cigar32): # convert the 32-bit CIGAR encoding to Python array
|
||||||
if cs or MD: # generate the cs and/or the MD tag, if requested
|
c = h.cigar32[k]
|
||||||
if cs:
|
cigar.append([c>>4, c&0xf])
|
||||||
l_cs_str = cmappy.mm_gen_cs(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq, 1)
|
if cs or MD: # generate the cs and/or the MD tag, if requested
|
||||||
_cs = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
|
if cs:
|
||||||
if MD:
|
l_cs_str = cmappy.mm_gen_cs(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq, 1)
|
||||||
l_cs_str = cmappy.mm_gen_MD(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq)
|
_cs = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
|
||||||
_MD = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
|
if MD:
|
||||||
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, _cs, _MD)
|
l_cs_str = cmappy.mm_gen_MD(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq)
|
||||||
cmappy.mm_free_reg1(®s[i])
|
_MD = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
|
||||||
free(regs)
|
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, _cs, _MD)
|
||||||
free(cs_str)
|
cmappy.mm_free_reg1(®s[i])
|
||||||
|
i += 1
|
||||||
|
finally:
|
||||||
|
while i < n_regs:
|
||||||
|
cmappy.mm_free_reg1(®s[i])
|
||||||
|
i += 1
|
||||||
|
free(regs)
|
||||||
|
free(cs_str)
|
||||||
|
|
||||||
def seq(self, str name, int start=0, int end=0x7fffffff):
|
def seq(self, str name, int start=0, int end=0x7fffffff):
|
||||||
cdef int l
|
cdef int l
|
||||||
cdef char *s = cmappy.mappy_fetch_seq(self._idx, name.encode(), start, end, &l)
|
cdef char *s
|
||||||
|
if self._idx == NULL: return
|
||||||
|
s = cmappy.mappy_fetch_seq(self._idx, name.encode(), start, end, &l)
|
||||||
if l == 0: return None
|
if l == 0: return None
|
||||||
r = s[:l] if isinstance(s, str) else s[:l].decode()
|
r = s[:l] if isinstance(s, str) else s[:l].decode()
|
||||||
free(s)
|
free(s)
|
||||||
@@ -230,6 +232,17 @@ cdef class Aligner:
|
|||||||
@property
|
@property
|
||||||
def n_seq(self): return self._idx.n_seq
|
def n_seq(self): return self._idx.n_seq
|
||||||
|
|
||||||
|
@property
|
||||||
|
def seq_names(self):
|
||||||
|
cdef char *p
|
||||||
|
if self._idx == NULL: return
|
||||||
|
sn = []
|
||||||
|
for i in range(self._idx.n_seq):
|
||||||
|
p = self._idx.seq[i].name
|
||||||
|
s = p if isinstance(p, str) else p.decode()
|
||||||
|
sn.append(s)
|
||||||
|
return sn
|
||||||
|
|
||||||
def fastx_read(fn, read_comment=False):
|
def fastx_read(fn, read_comment=False):
|
||||||
cdef cmappy.kseq_t *ks
|
cdef cmappy.kseq_t *ks
|
||||||
ks = cmappy.mm_fastx_open(str.encode(fn))
|
ks = cmappy.mm_fastx_open(str.encode(fn))
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#include "mmpriv.h"
|
||||||
|
#include "kalloc.h"
|
||||||
|
#include "ksort.h"
|
||||||
|
|
||||||
|
mm_seed_t *mm_seed_collect_all(void *km, const mm_idx_t *mi, const mm128_v *mv, int32_t *n_m_)
|
||||||
|
{
|
||||||
|
mm_seed_t *m;
|
||||||
|
size_t i;
|
||||||
|
int32_t k;
|
||||||
|
m = (mm_seed_t*)kmalloc(km, mv->n * sizeof(mm_seed_t));
|
||||||
|
for (i = k = 0; i < mv->n; ++i) {
|
||||||
|
const uint64_t *cr;
|
||||||
|
mm_seed_t *q;
|
||||||
|
mm128_t *p = &mv->a[i];
|
||||||
|
uint32_t q_pos = (uint32_t)p->y, q_span = p->x & 0xff;
|
||||||
|
int t;
|
||||||
|
cr = mm_idx_get(mi, p->x>>8, &t);
|
||||||
|
if (t == 0) continue;
|
||||||
|
q = &m[k++];
|
||||||
|
q->q_pos = q_pos, q->q_span = q_span, q->cr = cr, q->n = t, q->seg_id = p->y >> 32;
|
||||||
|
q->is_tandem = q->flt = 0;
|
||||||
|
if (i > 0 && p->x>>8 == mv->a[i - 1].x>>8) q->is_tandem = 1;
|
||||||
|
if (i < mv->n - 1 && p->x>>8 == mv->a[i + 1].x>>8) q->is_tandem = 1;
|
||||||
|
}
|
||||||
|
*n_m_ = k;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MAX_MAX_HIGH_OCC 128
|
||||||
|
|
||||||
|
void mm_seed_select(int32_t n, mm_seed_t *a, int len, int max_occ, int max_max_occ, int dist)
|
||||||
|
{ // for high-occ minimizers, choose up to max_high_occ in each high-occ streak
|
||||||
|
extern void ks_heapdown_uint64_t(size_t i, size_t n, uint64_t*);
|
||||||
|
extern void ks_heapmake_uint64_t(size_t n, uint64_t*);
|
||||||
|
int32_t i, last0, m;
|
||||||
|
uint64_t b[MAX_MAX_HIGH_OCC]; // this is to avoid a heap allocation
|
||||||
|
|
||||||
|
if (n == 0 || n == 1) return;
|
||||||
|
for (i = m = 0; i < n; ++i)
|
||||||
|
if (a[i].n > max_occ) ++m;
|
||||||
|
if (m == 0) return; // no high-frequency k-mers; do nothing
|
||||||
|
for (i = 0, last0 = -1; i <= n; ++i) {
|
||||||
|
if (i == n || a[i].n <= max_occ) {
|
||||||
|
if (i - last0 > 1) {
|
||||||
|
int32_t ps = last0 < 0? 0 : (uint32_t)a[last0].q_pos>>1;
|
||||||
|
int32_t pe = i == n? len : (uint32_t)a[i].q_pos>>1;
|
||||||
|
int32_t j, k, st = last0 + 1, en = i;
|
||||||
|
int32_t max_high_occ = (int32_t)((double)(pe - ps) / dist + .499);
|
||||||
|
if (max_high_occ > 0) {
|
||||||
|
if (max_high_occ > MAX_MAX_HIGH_OCC)
|
||||||
|
max_high_occ = MAX_MAX_HIGH_OCC;
|
||||||
|
for (j = st, k = 0; j < en && k < max_high_occ; ++j, ++k)
|
||||||
|
b[k] = (uint64_t)a[j].n<<32 | j;
|
||||||
|
ks_heapmake_uint64_t(k, b); // initialize the binomial heap
|
||||||
|
for (; j < en; ++j) { // if there are more, choose top max_high_occ
|
||||||
|
if (a[j].n < (int32_t)(b[0]>>32)) { // then update the heap
|
||||||
|
b[0] = (uint64_t)a[j].n<<32 | j;
|
||||||
|
ks_heapdown_uint64_t(0, k, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (j = 0; j < k; ++j) a[(uint32_t)b[j]].flt = 1;
|
||||||
|
}
|
||||||
|
for (j = st; j < en; ++j) a[j].flt ^= 1;
|
||||||
|
for (j = st; j < en; ++j)
|
||||||
|
if (a[j].n > max_max_occ)
|
||||||
|
a[j].flt = 1;
|
||||||
|
}
|
||||||
|
last0 = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_seed_t *mm_collect_matches(void *km, int *_n_m, int qlen, int max_occ, int max_max_occ, int dist, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos)
|
||||||
|
{
|
||||||
|
int rep_st = 0, rep_en = 0, n_m, n_m0;
|
||||||
|
size_t i;
|
||||||
|
mm_seed_t *m;
|
||||||
|
*n_mini_pos = 0;
|
||||||
|
*mini_pos = (uint64_t*)kmalloc(km, mv->n * sizeof(uint64_t));
|
||||||
|
m = mm_seed_collect_all(km, mi, mv, &n_m0);
|
||||||
|
if (dist > 0 && max_max_occ > max_occ) {
|
||||||
|
mm_seed_select(n_m0, m, qlen, max_occ, max_max_occ, dist);
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < n_m0; ++i)
|
||||||
|
if (m[i].n > max_occ)
|
||||||
|
m[i].flt = 1;
|
||||||
|
}
|
||||||
|
for (i = 0, n_m = 0, *rep_len = 0, *n_a = 0; i < n_m0; ++i) {
|
||||||
|
mm_seed_t *q = &m[i];
|
||||||
|
//fprintf(stderr, "X\t%d\t%d\t%d\n", q->q_pos>>1, q->n, q->flt);
|
||||||
|
if (q->flt) {
|
||||||
|
int en = (q->q_pos >> 1) + 1, st = en - q->q_span;
|
||||||
|
if (st > rep_en) {
|
||||||
|
*rep_len += rep_en - rep_st;
|
||||||
|
rep_st = st, rep_en = en;
|
||||||
|
} else rep_en = en;
|
||||||
|
} else {
|
||||||
|
*n_a += q->n;
|
||||||
|
(*mini_pos)[(*n_mini_pos)++] = (uint64_t)q->q_span<<32 | q->q_pos>>1;
|
||||||
|
m[n_m++] = *q;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*rep_len += rep_en - rep_st;
|
||||||
|
*_n_m = n_m;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
@@ -4,16 +4,6 @@ except ImportError:
|
|||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
from distutils.extension import Extension
|
from distutils.extension import Extension
|
||||||
|
|
||||||
cmdclass = {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
from Cython.Build import build_ext
|
|
||||||
except ImportError: # without Cython
|
|
||||||
module_src = 'python/mappy.c'
|
|
||||||
else: # with Cython
|
|
||||||
module_src = 'python/mappy.pyx'
|
|
||||||
cmdclass['build_ext'] = build_ext
|
|
||||||
|
|
||||||
import sys, platform
|
import sys, platform
|
||||||
|
|
||||||
sys.path.append('python')
|
sys.path.append('python')
|
||||||
@@ -33,7 +23,7 @@ def readme():
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'mappy',
|
name = 'mappy',
|
||||||
version = '2.13',
|
version = '2.22',
|
||||||
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(),
|
||||||
@@ -42,8 +32,8 @@ setup(
|
|||||||
license = 'MIT',
|
license = 'MIT',
|
||||||
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', 'options.c',
|
sources = ['python/mappy.pyx', 'align.c', 'bseq.c', 'lchain.c', 'seed.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', 'splitidx.c'],
|
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c', 'splitidx.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',
|
||||||
@@ -62,4 +52,4 @@ setup(
|
|||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Intended Audience :: Science/Research',
|
'Intended Audience :: Science/Research',
|
||||||
'Topic :: Scientific/Engineering :: Bio-Informatics'],
|
'Topic :: Scientific/Engineering :: Bio-Informatics'],
|
||||||
cmdclass = cmdclass)
|
setup_requires=["cython"])
|
||||||
|
|||||||
+11
-7
@@ -2,6 +2,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
#include "mmpriv.h"
|
#include "mmpriv.h"
|
||||||
|
|
||||||
FILE *mm_split_init(const char *prefix, const mm_idx_t *mi)
|
FILE *mm_split_init(const char *prefix, const mm_idx_t *mi)
|
||||||
@@ -11,14 +12,17 @@ FILE *mm_split_init(const char *prefix, const mm_idx_t *mi)
|
|||||||
uint32_t i, k = mi->k;
|
uint32_t i, k = mi->k;
|
||||||
fn = (char*)calloc(strlen(prefix) + 10, 1);
|
fn = (char*)calloc(strlen(prefix) + 10, 1);
|
||||||
sprintf(fn, "%s.%.4d.tmp", prefix, mi->index);
|
sprintf(fn, "%s.%.4d.tmp", prefix, mi->index);
|
||||||
fp = fopen(fn, "wb");
|
if ((fp = fopen(fn, "wb")) == NULL) {
|
||||||
assert(fp);
|
if (mm_verbose >= 1)
|
||||||
|
fprintf(stderr, "[ERROR]\033[1;31m failed to write to temporary file '%s'\033[0m: %s\n", fn, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
mm_err_fwrite(&k, 4, 1, fp);
|
mm_err_fwrite(&k, 4, 1, fp);
|
||||||
mm_err_fwrite(&mi->n_seq, 4, 1, fp);
|
mm_err_fwrite(&mi->n_seq, 4, 1, fp);
|
||||||
for (i = 0; i < mi->n_seq; ++i) {
|
for (i = 0; i < mi->n_seq; ++i) {
|
||||||
uint8_t l;
|
uint32_t l;
|
||||||
l = strlen(mi->seq[i].name);
|
l = strlen(mi->seq[i].name);
|
||||||
mm_err_fwrite(&l, 1, 1, fp);
|
mm_err_fwrite(&l, 1, 4, fp);
|
||||||
mm_err_fwrite(mi->seq[i].name, 1, l, fp);
|
mm_err_fwrite(mi->seq[i].name, 1, l, fp);
|
||||||
mm_err_fwrite(&mi->seq[i].len, 4, 1, fp);
|
mm_err_fwrite(&mi->seq[i].len, 4, 1, fp);
|
||||||
}
|
}
|
||||||
@@ -38,7 +42,7 @@ mm_idx_t *mm_split_merge_prep(const char *prefix, int n_splits, FILE **fp, uint3
|
|||||||
sprintf(fn, "%s.%.4d.tmp", prefix, i);
|
sprintf(fn, "%s.%.4d.tmp", prefix, i);
|
||||||
if ((fp[i] = fopen(fn, "rb")) == 0) {
|
if ((fp[i] = fopen(fn, "rb")) == 0) {
|
||||||
if (mm_verbose >= 1)
|
if (mm_verbose >= 1)
|
||||||
fprintf(stderr, "ERROR: failed to open temporary file '%s'\n", fn);
|
fprintf(stderr, "ERROR: failed to open temporary file '%s': %s\n", fn, strerror(errno));
|
||||||
for (j = 0; j < i; ++j)
|
for (j = 0; j < i; ++j)
|
||||||
fclose(fp[j]);
|
fclose(fp[j]);
|
||||||
free(fn);
|
free(fn);
|
||||||
@@ -57,8 +61,8 @@ mm_idx_t *mm_split_merge_prep(const char *prefix, int n_splits, FILE **fp, uint3
|
|||||||
for (i = j = 0; i < n_splits; ++i) {
|
for (i = j = 0; i < n_splits; ++i) {
|
||||||
uint32_t k;
|
uint32_t k;
|
||||||
for (k = 0; k < n_seq_part[i]; ++k, ++j) {
|
for (k = 0; k < n_seq_part[i]; ++k, ++j) {
|
||||||
uint8_t l;
|
uint32_t l;
|
||||||
mm_err_fread(&l, 1, 1, fp[i]);
|
mm_err_fread(&l, 1, 4, fp[i]);
|
||||||
mi->seq[j].name = (char*)calloc(l + 1, 1);
|
mi->seq[j].name = (char*)calloc(l + 1, 1);
|
||||||
mm_err_fread(mi->seq[j].name, 1, l, fp[i]);
|
mm_err_fread(mi->seq[j].name, 1, l, fp[i]);
|
||||||
mm_err_fread(&mi->seq[j].len, 4, 1, fp[i]);
|
mm_err_fread(&mi->seq[j].len, 4, 1, fp[i]);
|
||||||
|
|||||||
@@ -338,3 +338,114 @@
|
|||||||
Title = {Introducing difference recurrence relations for faster semi-global alignment of long sequences},
|
Title = {Introducing difference recurrence relations for faster semi-global alignment of long sequences},
|
||||||
Volume = {19},
|
Volume = {19},
|
||||||
Year = {2018}}
|
Year = {2018}}
|
||||||
|
|
||||||
|
@article{Li:2018ab,
|
||||||
|
Author = {Li, Heng},
|
||||||
|
Journal = {Bioinformatics},
|
||||||
|
Pages = {3094-3100},
|
||||||
|
Title = {Minimap2: pairwise alignment for nucleotide sequences},
|
||||||
|
Volume = {34},
|
||||||
|
Year = {2018}}
|
||||||
|
|
||||||
|
@article{Jain:2020aa,
|
||||||
|
Author = {Jain, Chirag and others},
|
||||||
|
Journal = {Bioinformatics},
|
||||||
|
Pages = {i111-i118},
|
||||||
|
Title = {Weighted minimizer sampling improves long read mapping},
|
||||||
|
Volume = {36},
|
||||||
|
Year = {2020}}
|
||||||
|
|
||||||
|
@article{Miga:2020aa,
|
||||||
|
Author = {Miga, Karen H and others},
|
||||||
|
Journal = {Nature},
|
||||||
|
Pages = {79-84},
|
||||||
|
Title = {Telomere-to-telomere assembly of a complete human {X} chromosome},
|
||||||
|
Volume = {585},
|
||||||
|
Year = {2020}}
|
||||||
|
|
||||||
|
@article {Jain2020.11.01.363887,
|
||||||
|
author = {Jain, Chirag and others},
|
||||||
|
title = {A long read mapping method for highly repetitive reference sequences},
|
||||||
|
elocation-id = {2020.11.01.363887},
|
||||||
|
year = {2020},
|
||||||
|
doi = {10.1101/2020.11.01.363887},
|
||||||
|
publisher = {Cold Spring Harbor Laboratory},
|
||||||
|
abstract = {About 5-10\% of the human genome remains inaccessible for functional analysis due to the presence of repetitive sequences such as segmental duplications and tandem repeat arrays. To enable high-quality resequencing of personal genomes, it is crucial to support end-to-end genome variant discovery using repeat-aware read mapping methods. In this study, we highlight the fact that existing long read mappers often yield incorrect alignments and variant calls within long, near-identical repeats, as they remain vulnerable to allelic bias. In the presence of a non-reference allele within a repeat, a read sampled from that region could be mapped to an incorrect repeat copy because the standard pairwise sequence alignment scoring system penalizes true variants.To address the above problem, we propose a novel, long read mapping method that addresses allelic bias by making use of minimal confidently alignable substrings (MCASs). MCASs are formulated as minimal length substrings of a read that have unique alignments to a reference locus with sufficient mapping confidence (i.e., a mapping quality score above a user-specified threshold). This approach treats each read mapping as a collection of confident sub-alignments, which is more tolerant of structural variation and more sensitive to paralog-specific variants (PSVs) within repeats. We mathematically define MCASs and discuss an exact algorithm as well as a practical heuristic to compute them. The proposed method, referred to as Winnowmap2, is evaluated using simulated as well as real long read benchmarks using the recently completed gapless assemblies of human chromosomes X and 8 as a reference. We show that Winnowmap2 successfully addresses the issue of allelic bias, enabling more accurate downstream variant calls in repetitive sequences. As an example, using simulated PacBio HiFi reads and structural variants in chromosome 8, Winnowmap2 alignments achieved the lowest false-negative and false-positive rates (1.89\%, 1.89\%) for calling structural variants within near-identical repeats compared to minimap2 (39.62\%, 5.88\%) and NGMLR (56.60\%, 36.11\%) respectively.Winnowmap2 code is accessible at https://github.com/marbl/WinnowmapCompeting Interest StatementThe authors have declared no competing interest.},
|
||||||
|
URL = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887},
|
||||||
|
eprint = {https://www.biorxiv.org/content/early/2020/11/02/2020.11.01.363887.full.pdf},
|
||||||
|
journal = {bioRxiv}
|
||||||
|
}
|
||||||
|
|
||||||
|
@article{Li:2020aa,
|
||||||
|
Author = {Li, Heng and others},
|
||||||
|
Journal = {Genome Biol},
|
||||||
|
Pages = {265},
|
||||||
|
Title = {The design and construction of reference pangenome graphs with minigraph},
|
||||||
|
Volume = {21},
|
||||||
|
Year = {2020}}
|
||||||
|
|
||||||
|
@article{Ren:2021aa,
|
||||||
|
Author = {Ren, Jingwen and Chaisson, Mark J P},
|
||||||
|
Journal = {PLoS Comput Biol},
|
||||||
|
Pages = {e1009078},
|
||||||
|
Title = {lra: A long read aligner for sequences and contigs},
|
||||||
|
Volume = {17},
|
||||||
|
Year = {2021}}
|
||||||
|
|
||||||
|
@inproceedings{DBLP:conf/wabi/AbouelhodaO03,
|
||||||
|
Author = {Mohamed Ibrahim Abouelhoda and Enno Ohlebusch},
|
||||||
|
Booktitle = {Algorithms in Bioinformatics, Third International Workshop, {WABI} 2003, Budapest, Hungary, September 15-20, 2003, Proceedings},
|
||||||
|
Crossref = {DBLP:conf/wabi/2003},
|
||||||
|
Pages = {1--16},
|
||||||
|
Title = {A Local Chaining Algorithm and Its Applications in Comparative Genomics},
|
||||||
|
Year = {2003}}
|
||||||
|
|
||||||
|
@article{Ono:2021aa,
|
||||||
|
Author = {Ono, Yukiteru and others},
|
||||||
|
Journal = {Bioinformatics},
|
||||||
|
Pages = {589-595},
|
||||||
|
Title = {{PBSIM2}: a simulator for long-read sequencers with a novel generative model of quality scores},
|
||||||
|
Volume = {37},
|
||||||
|
Year = {2021}}
|
||||||
|
|
||||||
|
@article{Sedlazeck:2018ab,
|
||||||
|
Author = {Sedlazeck, Fritz J and others},
|
||||||
|
Journal = {Nat Methods},
|
||||||
|
Pages = {461-468},
|
||||||
|
Title = {Accurate detection of complex structural variations using single-molecule sequencing},
|
||||||
|
Volume = {15},
|
||||||
|
Year = {2018}}
|
||||||
|
|
||||||
|
@article{Jeffares:2017aa,
|
||||||
|
Author = {Jeffares, Daniel C and others},
|
||||||
|
Journal = {Nat Commun},
|
||||||
|
Pages = {14061},
|
||||||
|
Title = {Transient structural variations have strong effects on quantitative traits and reproductive isolation in fission yeast},
|
||||||
|
Volume = {8},
|
||||||
|
Year = {2017}}
|
||||||
|
|
||||||
|
@article{Zook:2020aa,
|
||||||
|
Author = {Zook, Justin M and others},
|
||||||
|
Journal = {Nat Biotechnol},
|
||||||
|
Pages = {1347-1355},
|
||||||
|
Title = {A robust benchmark for detection of germline large deletions and insertions},
|
||||||
|
Volume = {38},
|
||||||
|
Year = {2020}}
|
||||||
|
|
||||||
|
@article{Harpak:2017aa,
|
||||||
|
Author = {Harpak, Arbel and others},
|
||||||
|
Journal = {Proc Natl Acad Sci U S A},
|
||||||
|
Pages = {12779-12784},
|
||||||
|
Title = {Frequent nonallelic gene conversion on the human lineage and its effect on the divergence of gene duplicates},
|
||||||
|
Volume = {114},
|
||||||
|
Year = {2017}}
|
||||||
|
|
||||||
|
@article{Li:2018aa,
|
||||||
|
Author = {Li, Heng and others},
|
||||||
|
Journal = {Nat Methods},
|
||||||
|
Month = {Aug},
|
||||||
|
Number = {8},
|
||||||
|
Pages = {595-597},
|
||||||
|
Title = {A synthetic-diploid benchmark for accurate variant-calling evaluation},
|
||||||
|
Volume = {15},
|
||||||
|
Year = {2018}}
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
\documentclass{bioinfo}
|
||||||
|
\copyrightyear{2021}
|
||||||
|
\pubyear{2021}
|
||||||
|
|
||||||
|
\usepackage{graphicx}
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{url}
|
||||||
|
\usepackage{amsmath}
|
||||||
|
\usepackage[ruled,vlined]{algorithm2e}
|
||||||
|
\newcommand\mycommfont[1]{\footnotesize\rmfamily{\it #1}}
|
||||||
|
\SetCommentSty{mycommfont}
|
||||||
|
\SetKwComment{Comment}{$\triangleright$\ }{}
|
||||||
|
|
||||||
|
\usepackage{natbib}
|
||||||
|
\bibliographystyle{apalike}
|
||||||
|
|
||||||
|
\DeclareMathOperator*{\argmax}{argmax}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\firstpage{1}
|
||||||
|
|
||||||
|
\title[Improvements to minimap2]{New strategies to improve minimap2 alignment accuracy}
|
||||||
|
\author[Li]{Heng Li$^{1,2}$}
|
||||||
|
\address{$^1$Dana-Farber Cancer Institute, 450 Brookline Ave, Boston, MA 02215, USA,
|
||||||
|
$^2$Harvard Medical School, 10 Shattuck St, Boston, MA 02215, USA}
|
||||||
|
|
||||||
|
\maketitle
|
||||||
|
|
||||||
|
\begin{abstract}
|
||||||
|
|
||||||
|
\section{Summary:} We present several recent improvements to minimap2, a
|
||||||
|
versatile pairwise aligner for nucleotide sequences. Now minimap2 v2.22 can
|
||||||
|
more accurately map long reads to highly repetitive regions and align through
|
||||||
|
insertions or deletions up to 100kb by default, addressing major weakness in
|
||||||
|
minimap2 v2.18 or earlier.
|
||||||
|
|
||||||
|
\section{Availability and implementation:}
|
||||||
|
\href{https://github.com/lh3/minimap2}{https://github.com/lh3/minimap2}
|
||||||
|
|
||||||
|
\section{Contact:} hli@ds.dfci.harvard.edu
|
||||||
|
\end{abstract}
|
||||||
|
|
||||||
|
\section{Introduction}
|
||||||
|
Minimap2~\citep{Li:2018ab} is widely used for maping long sequence
|
||||||
|
reads and assembly contigs. \citet{Jain:2020aa} found minimap2 v2.18 or earlier occasionally
|
||||||
|
misaligned reads from highly repetitive regions as minimap2 ignored seeds of
|
||||||
|
high occurrence. They also noticed minimap2 may misplace reads with structural
|
||||||
|
variations (SVs) in such regions~\citep{Jain2020.11.01.363887}. These
|
||||||
|
misalignments have become a pressing issue in the advent of
|
||||||
|
temolere-to-telomore human assembly~\citep{Miga:2020aa}. Meanwhile, old minimap2
|
||||||
|
was unable to efficiently align long insertions/deletions (INDELs) and often
|
||||||
|
breaks an alignment around variable-number tandem repeats (VNTRs). This has
|
||||||
|
inspired new chaining algorithms~\citep{Li:2020aa,Ren:2021aa} which are not
|
||||||
|
integrated into minimap2. Here we will describe recent efforts implemented
|
||||||
|
in v2.19 through v2.22 to improve mapping results.
|
||||||
|
|
||||||
|
\begin{methods}
|
||||||
|
\section{Methods}
|
||||||
|
|
||||||
|
\subsection{Rescuing high-occurrence $k$-mers}
|
||||||
|
Minimap2 keeps all $k$-mer minimizers during indexing. Its original
|
||||||
|
implementation only selected low-occurrence minimizers during mapping. The
|
||||||
|
cutoff is a few hundred for mapping long reads against a human genome. If a
|
||||||
|
read habors only a few or even no low-occurrence minimizers, it will fail
|
||||||
|
chaining due to insufficient anchors.
|
||||||
|
|
||||||
|
To resolve this issue, we implemented a new heuristic to add additional
|
||||||
|
minimizers. Suppose we are looking at two adjacent low-occurence $k$-mers
|
||||||
|
located at position $x_1$ and $x_2$, respectively. If $|x_1-x_2|\ge500$,
|
||||||
|
minimap2 v2.22 additionally selects $\lfloor|x_1-x_2|/500\rfloor$ minimizers
|
||||||
|
of the lowest occurrence among minimizers between $x_1$ and $x_2$.
|
||||||
|
We use a binary heap data
|
||||||
|
structure to select minimizers of the lowest occurrence in this interval.
|
||||||
|
This strategy adds necessary anchors at the cost of increasing total alignment
|
||||||
|
time by a few percent on real data.
|
||||||
|
|
||||||
|
\subsection{Aligning through longer INDELs}
|
||||||
|
The original minimap2 may fail to align long INDELs due to its chaining
|
||||||
|
heuristics. Briefly, minimap2 applies dynamic programming (DP) to chain
|
||||||
|
minimizer anchors. This is a quadratic algorithm, which is slow for chaining
|
||||||
|
contigs. For acceptable performance, the original minimap2 uses a 500bp band by
|
||||||
|
default. If there is an INDEL longer than 500bp and the two chains around the INDEL
|
||||||
|
have no overlaps on either the query or the reference sequence, minimap2 may
|
||||||
|
join the two short chains later at a later step. We call it the
|
||||||
|
long-join heuristic. This heuristic may fail around VNTRs because short chains
|
||||||
|
often have overlaps in VNTRs. More subtly, minimap2 may escape the inner DP
|
||||||
|
loop early, again for performance, if the chaining result is not improved for
|
||||||
|
50 iterations. When there is a copy number change in a long segmental
|
||||||
|
duplication, the early escape may break around the event even if users
|
||||||
|
specify a large band.
|
||||||
|
|
||||||
|
In minigraph~\citep{Li:2020aa}, we developed a new chaining algorithm that
|
||||||
|
finds short INDELs with DP-based chaining and goes through long INDELs with a
|
||||||
|
subquadratic algorithm~\citep{DBLP:conf/wabi/AbouelhodaO03}. We ported the same
|
||||||
|
algorithm to minimap2 for contig mapping. For long-read mapping, the minigraph
|
||||||
|
algorithm is slower. Minimap2 v2.22 now still uses the DP-based algorithm to
|
||||||
|
find short chains and then invokes the minigraph algorithm to rechain anchors in
|
||||||
|
these short chains. The rechaining step achieves the same goal as long-join
|
||||||
|
but is more reliable as it can resolve overlaps between short chains. The old
|
||||||
|
long-join heuristic has since been removed.
|
||||||
|
|
||||||
|
\subsection{Properly mapping long reads with SVs}
|
||||||
|
The original minimap2 ranks an alignment by its Smith-Waterman score and
|
||||||
|
outputs the best scoring alignment. However, when there are SVs on the read,
|
||||||
|
the best scoring alignment is sometimes not the correct alignment.
|
||||||
|
\citet{Jain2020.11.01.363887} resolved this dilemma by altering the mapping
|
||||||
|
algorithm.
|
||||||
|
|
||||||
|
In our view, this problem is rooted in impropriate scoring: affine-gap penalty
|
||||||
|
over-penalizes a long INDEL that was often evolutionarily created in one event.
|
||||||
|
We should not penalize a SV linearly in its length. Minimap2 v2.22 rescores
|
||||||
|
an alignment with the following scoring function. Suppose an alignment consists
|
||||||
|
of $M$ matching bases, $N$ substitutions and $G$ gap opens, we empirically
|
||||||
|
score the alignment with
|
||||||
|
$$
|
||||||
|
M-\frac{N+G}{2d}-\sum_{i=1}^G\log_2(1+g_i)
|
||||||
|
$$
|
||||||
|
where $g_i\ge1$ is the length of the $i$-th gap and
|
||||||
|
$$
|
||||||
|
d=\max\left\{\frac{N+G}{M+N+G},0.02\right\}
|
||||||
|
$$
|
||||||
|
Here $d$ approximates per-base sequence divergence with the smallest value set
|
||||||
|
to 2\%. As an analogy to affine-gap scoring, the matching score in our scheme
|
||||||
|
is 1, the mismatch and gap open penalties are both $1/2d$ and the gap extension
|
||||||
|
penalty is a logarithm function of the gap length. Our scoring gives a long SV
|
||||||
|
a much milder penalty. In terms of time complexity, scoring an alignment is
|
||||||
|
linear in the length of the alignment. Time spent on rescoring is negligible in
|
||||||
|
practice.
|
||||||
|
|
||||||
|
%If we assume sequences evolve under a duplication-mutation model, we may have a
|
||||||
|
%better way to choose the best alignment. If a long read can be mapped to $n$
|
||||||
|
%loci, we can take the read as the template and build a
|
||||||
|
%pseudo-multi-sequence-alignment (pMSA) of $n+1$ sequences. In this pMSA, we say
|
||||||
|
%a site on the read is informative if the $n$ reference subsequences differ at
|
||||||
|
%the position.
|
||||||
|
|
||||||
|
\end{methods}
|
||||||
|
|
||||||
|
\section{Results}
|
||||||
|
|
||||||
|
\begin{table}
|
||||||
|
\processtable{Evaluation of minimap2 v2.22}
|
||||||
|
{\footnotesize\label{tab:1}\begin{tabular}{p{4.2cm}rrrr}
|
||||||
|
\toprule
|
||||||
|
$[$Benchmark$]$ Metric & v2.22 & v2.18 & Winno & lra \\
|
||||||
|
\midrule
|
||||||
|
$[$sim-map$]$ \% mapped reads at Q10 & 97.9 & 97.6 & {\bf 99.0} & 97.3 \\
|
||||||
|
$[$sim-map$]$ err. rate at Q10 (phredQ) & {\bf 52} & {\bf 52} & 38 & 24 \\
|
||||||
|
$[$winno-cmp$]$ rate of diff. (phredQ) & {\bf 41} & 37 & N/A & 18 \\
|
||||||
|
$[$sim-sv$]$ \% false negative rate & {\bf 0.5} & 2.0 & {\bf 0.5} & 1.4 \\
|
||||||
|
$[$sim-sv$]$ \% false discovery rate & {\bf 0.0} & 0.1 & {\bf 0.0} & 0.1 \\
|
||||||
|
$[$real-sv-1k$]$ \% false negative rate & {\bf 7.3} & 20.0 & 13.0 & N/A \\
|
||||||
|
$[$real-sv-1k$]$ \% false discovery rate & 2.7 & {\bf 2.4} & 2.7 & N/A \\
|
||||||
|
\botrule
|
||||||
|
\end{tabular}}
|
||||||
|
{In $[$sim-map$]$, 152,713 reads were simulated from the CHM13 telomere-to-telomere assembly v1.1
|
||||||
|
(AC: GCA\_009914755.3) with pbsim2~\citep{Ono:2021aa}: ``pbsim2 -{}-hmm\_model R94.model -{}-length-min
|
||||||
|
5000 -{}-length-mean 20000 -{}-accuracy-mean 0.95''. Alignments of mapping quality
|
||||||
|
10 or higher were evaluated by ``paftools.js mapeval''. The mapping error rate
|
||||||
|
is measured in the phred scale: if the error rate is $e$, $-10\log_{10}e$ is
|
||||||
|
reported in the table. In $[$winno-cmp$]$, 1.39 million CHM13 HiFi reads from
|
||||||
|
SRR11292121 were mapped against CHM13. 99.3\% of them were mapped by Winnowmap2
|
||||||
|
at mapping quality 10 or higher and were taken as ground truth to evaluate
|
||||||
|
minimap2 and lra with ``paftools.js pafcmp''. $[$sim-sv$]$ simulated 1,000
|
||||||
|
50bp to 1000bp INDELs from chr8 in CHM13 using SURVIVOR~\citep{Jeffares:2017aa} and simulated Nanopore
|
||||||
|
reads at 30 folds with the same pbsim2 command line. SVs were called with
|
||||||
|
``sniffles -q 10''~\citep{Sedlazeck:2018ab} and compared to the simulated truth with ``SURVIVOR eval
|
||||||
|
call.vcf truth.bed 50''. In $[$real-sv-1k$]$, small and long variants were
|
||||||
|
called by dipcall-0.3~\citep{Li:2018aa} for HG002 assemblies (AC: GCA\_018852605.1 and
|
||||||
|
GCA\_018852615.1) and compared to the GIAB truth~\citep{Zook:2020aa} using ``truvari -r 2000 -s
|
||||||
|
1000 -S 400 -{}-multimatch -{}-passonly'' which sets the minimum INDEL size to 1kb in evaluation. }
|
||||||
|
\end{table}
|
||||||
|
|
||||||
|
We evaluated minimap2 v2.22 along with v2.18, Winnowmap2 v2.03 and lra v1.3.2
|
||||||
|
(Table~\ref{tab:1}). Both versions of minimap2 achieved high mapping accuracy on
|
||||||
|
simulated Nanopore reads (sim-map). Winnowmap2 aligned more reads at mapping
|
||||||
|
quality 10 or higher (mapQ10). However, it may occasionally assign a high mapping
|
||||||
|
quality to a read with multiple identical best alignments. This reduced its
|
||||||
|
mapping accuracy.
|
||||||
|
|
||||||
|
In lack of groud truth for real data, so we took Winnowmap2 mapping as ground
|
||||||
|
truth to evaluate other mappers (winno-cmp). Out of 1,378,092 reads with mapQ10
|
||||||
|
alignments by Winnowmap2, minimap2 v2.22 could map all of them. 118 reads, less
|
||||||
|
than 0.01\% of all reads, were mapped differently by v2.22. 51 of them have
|
||||||
|
multiple identical best alignments. We believe these are more likely to be
|
||||||
|
Winnowmap2 errors. Most of the remaining 67 (=118-51) reads have multiple
|
||||||
|
highly similar but not identical alignments. We are not sure what are real
|
||||||
|
mapping errors.
|
||||||
|
|
||||||
|
The two benchmarks above only evaluate read mappings without variations.
|
||||||
|
To measure the mapping accuracy in the presence of SVs (sim-sv), we reproduced
|
||||||
|
the results by~\citep{Jain2020.11.01.363887}. Minimap2 v2.22 is as good as
|
||||||
|
Winnowmap2 now. Note that we were setting the Sniffles mapping quality
|
||||||
|
threshold to 10 in consistent with the benchmarks above. If we used the
|
||||||
|
default threshold 20, v2.22 would miss additional 0.5\% SVs, suggesting
|
||||||
|
minimap2 v2.22 could map variant reads correctly but with conservative mapping
|
||||||
|
quality. This observation is more about the interaction between mappers and
|
||||||
|
callers. Furthermore, the simulation here only considers a simple scenario in
|
||||||
|
evolution. Non-allelic gene conversions, which happen often in segmental
|
||||||
|
duplications~\citep{Harpak:2017aa}, would obscure the optimal mapping
|
||||||
|
strategies. How much such simple SV simulation informs real-world SV calling
|
||||||
|
remains a question.
|
||||||
|
|
||||||
|
To see if minimap2 v2.22 could improve long INDEL alignment, we ran dipcall on
|
||||||
|
contig-to-reference alignments and focused on INDELs longer than 1kb
|
||||||
|
(real-sv-1k). v2.22 is more sensitive at comparable specificity, confirming its
|
||||||
|
advantage in more contiguous alignment. lra is supposed to handle long INDELs
|
||||||
|
better, too. However, we could not get lra to work well with dipcall, so did
|
||||||
|
not report the numbers.
|
||||||
|
|
||||||
|
Minimap2 spends most computing time on base alignment. As recent improvements
|
||||||
|
in v2.22 incur little additional computing and do not change the base alignment
|
||||||
|
algorithm, the new version has similar performance to older verions. It is
|
||||||
|
consistently faster than Winnowmap2 by several times. Sometimes simple
|
||||||
|
heuristics can be as effective as more sophisticated yet slower solutions.
|
||||||
|
|
||||||
|
\section*{Acknowledgements}
|
||||||
|
We thank Arang Rhie and Chirag Jain for providing motivating examples where
|
||||||
|
older minimap2 underperforms.
|
||||||
|
|
||||||
|
\paragraph{Funding\textcolon} This work is funded by NHGRI grant R01HG010040.
|
||||||
|
|
||||||
|
\bibliography{minimap2}
|
||||||
|
|
||||||
|
\end{document}
|
||||||
Reference in New Issue
Block a user