Compare commits

...
226 Commits
Author SHA1 Message Date
Heng Li 15471bd629 Release minimap2-2.20 (r1061) 2021-05-27 15:26:04 -04:00
Heng Li ca19463268 r1060: safer ways to use -rNUM1,NUM2 2021-05-27 10:55:13 -04:00
Heng Li 4f8d1bc360 r1059: with --rmq, use the larger bandwidth 2021-05-26 23:01:49 -04:00
Heng Li 1776c0c645 missing seed.c in setup.py
Ok, I am not going to re-release again...
2021-05-26 21:36:09 -04:00
Heng Li 9febf532c1 Release minimap2-2.19 (r1057) 2021-05-26 21:23:42 -04:00
Heng Li cec23131e4 fixed a python compilation error
Caused by chain.c -> lchain.c
2021-05-26 21:20:48 -04:00
Heng Li ef09ccf104 Release minimap2-2.19 (r1055) 2021-05-26 21:01:03 -04:00
Heng Li e74dfd1aa9 r1054: fixed a memory leak 2021-05-26 12:32:04 -04:00
Heng Li f31705bb4a r1053: made junceval work with PAF 2021-05-26 11:54:46 -04:00
Heng Li 41d7ccb191 r1052: default -g to 5k 2021-05-24 16:46:16 -04:00
Heng Li 34a41197d7 r1051: added two internal parameters
rmq_rescue_size and rmq_rescue_ratio
2021-05-24 16:38:45 -04:00
Heng Li 9626b3e716 r1050: -r accepts two bandwidths 2021-05-24 16:29:21 -04:00
Heng Li 379728726a r1049: removed the long-join heuristics 2021-05-24 16:21:40 -04:00
Heng Li 4f91558160 r1048: rescue long gaps 2021-05-24 16:09:09 -04:00
Heng Li ec3bc6efd7 r1047: make gap penalty proportional to k-mer
closer to the older minimap2
2021-05-24 13:18:17 -04:00
Heng Li 8ec8866100 Merge branch 'master' into dev-rmq 2021-05-23 21:01:04 -04:00
Heng Li 9e7247cff9 sync python with recent changes 2021-05-23 21:00:15 -04:00
Ariel Erijman cd66777bfb small typo 2021-05-23 13:09:55 -04:00
Heng Li 5d7d25e92d Merge remote-tracking branch 'origin/master' 2021-05-23 13:08:52 -04:00
Heng Li 2a3793bbd2 clarify that map-hifi is for HEAD only
Resolves #747
2021-05-23 13:08:15 -04:00
Heng Li f97008a10e Merge branch 'master' into dev-rmq 2021-05-20 19:36:33 -04:00
Cornelius Roemer 10502e2a78 Fixed typo in Readme.md
deltion -> deletion
2021-05-14 15:38:30 -04:00
Don Kirkby 4422c0c6f9 Typo fix in Python README.
Thanks for sharing minimap2. Here's a little fix.
2021-05-14 15:38:12 -04:00
Heng Li 42a11e1d58 Changed Travis to Github Actions in README 2021-05-10 12:58:25 -04:00
Heng Li 76df351fa8 added github action 2021-05-10 12:55:58 -04:00
Heng Li d065d3bead Merge branch 'master' into dev-rmq 2021-05-10 12:42:57 -04:00
Heng Li ac146fe7bc r1035: failed to index under the --frag=yes mode
Resolves #734
2021-05-10 12:36:48 -04:00
Heng Li 6c96078ed0 r1034: changed multiple defaults; updated manpage 2021-05-03 22:51:34 -04:00
Heng Li bbb4f97e52 support RMQ 2021-05-03 09:27:04 -04:00
Heng Li b7f4d8a0f4 removed the old minimap2 chaining 2021-05-02 18:55:37 -04:00
Heng Li e81927e7a1 prepare to backport unimap/minigraph chaining 2021-05-02 18:25:49 -04:00
Heng Li f7dc5799c5 clarify CLR when necessary 2021-05-01 15:56:33 -04:00
Heng Li 817cb81cb0 Updated README for the HiFi preset 2021-05-01 15:47:25 -04:00
Heng Li 0f5608c4a4 r1028: backport minigraph -U 2021-05-01 15:41:39 -04:00
Heng Li e8823a3709 r1027: renamed hifi to map-hifi; changed default 2021-05-01 15:22:51 -04:00
Heng Li 7edeec67b0 r1026: fixed bugs in seed sampling add hifi 2021-05-01 15:07:56 -04:00
Heng Li feb92d32ea r1025: seed rescuring 2021-04-30 17:33:16 -04:00
Heng Li cdbd96be0c a bit refactoring for future changes 2021-04-30 11:24:53 -04:00
Heng Li ba52c79024 added code of conduct 2021-04-22 17:30:30 -04:00
Heng Li cd9ccfa069 r1022: check INDEL lengths in simple cases 2021-04-11 22:07:00 -04:00
Heng Li 86b716448c larger window size for longer INDELs 2021-04-11 16:08:29 -04:00
Heng Li 9ab95be1bb update END when it is not there 2021-04-11 12:59:21 -04:00
Heng Li b51e859945 make sure ins/del match 2021-04-11 11:47:14 -04:00
Heng Li a9037dc16c r1018: scripts for SV evaluation 2021-04-11 01:08:17 -04:00
Heng Li 9729fa99ad removed mappy.c 2021-04-09 13:48:16 -04:00
Heng Li b6ff332de1 Release minimap2-2.18 (r1015) 2021-04-09 13:33:34 -04:00
Heng Li 77abafaaf3 prepare for release 2021-04-09 13:18:56 -04:00
Heng Li 507d39af15 r1013: changed to a more accurate similarity est
Based on DOI:10.1101/2021.01.15.426881. One minimap2 reviewer suggested the
right formula to me but I thought the difference would be insignificant. I was
wrong.
2021-04-08 13:57:53 -04:00
Heng Li 827ca4b461 r1012: fixed an off-by-one bug; resolves #489 2021-04-07 23:31:31 -04:00
Marcus Stoiber d3dde2fdd4 Convert from spaces to tabs. 2021-04-05 11:55:10 -04:00
Marcus Stoiber 7db2e8d21a Convert python install from build_ext to setuptools setup_requires. 2021-04-05 11:55:10 -04:00
Heng Li 0b41dd26a2 r1009: fixed a compiler warning 2021-04-05 11:43:13 -04:00
Heng Li 2b47846cd6 r1008: don't parse space in BED 2021-04-05 11:41:00 -04:00
Heng Li 67dd906a80 bump travis python version to 3.9 2021-03-23 09:12:49 -04:00
Heng Li 1b0bb7b0ba require overlap ratio when considering centromere 2021-03-11 19:11:44 -05:00
Heng Li 1c4b7e8a48 explained --junc-bed in README 2021-03-06 19:44:24 -05:00
Heng Li ecbc399fa2 improved sveval 2021-03-06 19:44:13 -05:00
Heng Li 4dfd495cc2 added sveval 2021-02-15 14:49:36 -05:00
Heng Li 194b457e79 option to print errors only 2021-02-07 12:58:03 -05:00
Heng Li 75c8933511 evaluate large-scale misjoins 2021-02-07 12:34:13 -05:00
Heng Li 1025993469 print number of errors on each read 2021-01-29 14:08:21 -05:00
Heng Li a3253d1a6b added a command for simple VCF statistics 2021-01-14 12:24:38 -05:00
Heng Li 2da649d1d7 Merge remote-tracking branch 'origin/master' 2020-11-15 18:47:15 -05:00
Heng Li f995f55610 added --mask-len for #659 2020-08-21 11:12:50 -04:00
Armin Töpfer c9874e2dc5 Initialize r->p if ez->zdropped 2020-06-12 09:22:18 -04:00
Heng Li ccb0f7b05d added a new Makefile for simde 2020-04-25 22:43:29 -04:00
mbrcic 66db9da7d8 changed preprocessor conditionals for SIMDe 2020-04-22 19:50:59 +02:00
mbrcic 2b3403f094 fix for Neon after test. 2020-04-21 02:08:21 +02:00
mbrcic 3e16e4e39d Added documentation entry for added functionality, simde and no_simd. 2020-04-21 01:36:19 +02:00
mbrcic f47e8a525e SIMDe made optional. Include paths changes for SIMDe. 2020-04-21 01:08:32 +02:00
mbrcic c172df7d2d fix for Neon 2020-04-20 21:14:15 +02:00
mbrcic 9e6fdd376b Changed sse2neon with SIMDe. Added building non-SIMD version. 2020-04-20 18:28:06 +02:00
Heng Li 29f67a1666 r982: more accurate sum; output errors 2020-04-14 16:18:53 -04:00
Heng Li adde608a42 Merge remote-tracking branch 'refs/remotes/origin/master' 2020-04-14 15:52:57 -04:00
Heng Li f10dff78dc r981: asmgene to check duplicate genes 2020-04-14 15:52:36 -04:00
Jun Aruga d97bba9f27 travis: added arm64 test. 2020-04-13 08:33:03 -04:00
Heng Li 50775362bb r980: support auNGA 2020-04-10 21:36:59 -04:00
Heng Li 0a5e386359 r979: fixed asmgene wrong report. Resolves #581. 2020-04-06 19:57:15 -04:00
Heng Li cb56fb762a Merge branch 'master' of github.com:lh3/minimap2 2020-03-22 19:17:01 -04:00
Heng Li e2451e497a r975: asmstat without CIGAR/NM 2020-03-22 19:16:43 -04:00
Jared Simpson d2de282d21 remove second definition of kstring 2020-03-02 13:18:37 -05:00
Jared Simpson 48cb80ea94 change kstring_t integer storage size
This is for compatibility with kstring_t in htslib.
2020-02-28 09:35:51 -05:00
Heng Li 6a4b9f9082 r974: more informative msg on wrong FASTQ records
Resolves #510
2020-01-21 10:56:59 -05:00
Heng Li a7a01fe5bd r973: fixed compiling errors caused 2020-01-21 10:43:31 -05:00
Heng Li 9dceae59a0 r972: renamed --alt-diff to --alt-drop 2020-01-21 10:33:39 -05:00
Heng Li 20a3987082 Merge branch 'master' into alt 2020-01-21 09:17:50 -05:00
Heng Li eb3ed6993d support ALT mapping 2020-01-21 09:17:50 -05:00
Heng Li 7996f04008 r972: fixed negative de:f caused by ambiguous base 2020-01-21 09:14:37 -05:00
Heng Li d2e14705e7 r968: allow large mini_batch; resolves #491 2020-01-18 12:24:44 -05:00
Heng Li 24f50f38e8 r967: no duplicated @SQ lines with --split-prefix
resolves #527 and #400
2020-01-18 12:01:28 -05:00
Heng Li 04e015d803 r966: minimap2 returns 1 on file failure (#532) 2020-01-18 10:58:59 -05:00
Heng Li 040f74102c r965: added --chain-gap-scale for #540 2020-01-18 10:29:33 -05:00
Heng Li cdb7857841 r963: --junc-bonus not working; resolves #513 2020-01-06 22:03:50 -05:00
Heng Li 3c0d05d272 r962: abort given wrong RG line; resolves #541 2020-01-06 21:53:21 -05:00
Heng Li 47b646acbf r961: print indexed length 2020-01-06 21:13:33 -05:00
Heng Li a79cb3e991 Merge remote-tracking branch 'origin/master' 2019-12-23 17:33:56 -05:00
Heng Li 367aed4271 added the asan and tsan targets to Makefile 2019-12-23 17:33:10 -05:00
xdudiagnoa 081df6ac7d Fix example.c seq read logic
for every idx should map all input seqs
2019-11-11 00:46:07 -05:00
Torsten Seemann a3e7a575fb Add splice:hq to --help 2019-11-11 00:45:13 -05:00
Heng Li d90583b83c r954: fixed two potential undef behaviors (#443) 2019-07-18 09:17:08 -04:00
Heng Li 7fc03b0c32 r953: krealloc is buggy
Its use in minimap2 didn't trigger the bug, so the older minimap2 is still ok.
2019-07-18 09:13:30 -04:00
John Marshall 20c104ce8d Report errno on file opening failures and I/O errors
Add the underlying operating system error (usually "No such file" or
"Out of space" respectively, but highly informative when it is not)
to these error messages.
2019-07-17 09:04:02 -04:00
Marcus Stoiber 238b6bb3ea Fix memory leak in mappy.aligner.map. 2019-07-08 09:50:54 -04:00
Heng Li e026e18439 added the description of "SA" tag. Closes #438 2019-07-01 09:18:33 -04:00
Heng Li 58c2251b18 compatibility with GenBank GTP (resolves $422) 2019-06-11 09:16:03 -04:00
Heng Li 03dc8d5d97 test if index is built for #413 2019-06-07 09:11:11 -04:00
Heng Li 5cb61f8ee6 added FAQ 2019-06-06 10:47:33 -04:00
Heng Li c16a1742a3 Er... Tavis doesn't have python 3.7. 2019-05-11 20:06:48 -04:00
Heng Li 4bd5a018c2 test python 3.7 instead of 3.6 2019-05-11 20:05:06 -04:00
Heng Li 05974c80f1 r943: allow long ref name for --split-index
Resolved #394.
2019-05-10 15:39:41 -04:00
Heng Li 7bc87b4175 Release minimap2-2.17 (r941) 2019-05-04 23:49:17 -04:00
Heng Li 6762368cf0 r940: added the splice:hq preset
for high-quality CCS/mRNA splice alignment
2019-05-04 14:00:31 -04:00
Heng Li c2aec88b84 r938: added --sam-hit-only; resolved #377 2019-04-30 22:40:36 -04:00
Heng Li 97f67a2a0a r937: enlarge mm_mapopt_t::flag to 64 bits 2019-04-30 22:30:32 -04:00
Heng Li 189555503a potentially fix issue #372
Needs someone to confirm
2019-04-30 21:49:51 -04:00
Heng Li 69af86657e r935: fixed a cigar like 5I6D7I; resolved #392 2019-04-30 21:35:24 -04:00
Heng Li 49c6d83a8e r934: --junc-bed to read BED12 2019-04-28 20:12:28 -04:00
Heng Li f64e426a5a r933: resume versioning 2019-04-28 17:05:37 -04:00
Heng Li 2bb8cbbeef updated manpage 2019-04-28 17:02:49 -04:00
Heng Li e80759c97a --junc-bed apparently working
Also fixed an issue with splice alignment in the reverse strand, though this
should have a very minor effect in practice.
2019-04-28 16:47:12 -04:00
Heng Li f4c844b143 fixed a few simple bugs and leaks 2019-04-28 16:47:12 -04:00
Heng Li be171aa2dc implemented in exts; testing is the next 2019-04-28 16:47:12 -04:00
Heng Li cdc730d573 gff2bed to output junction BED 2019-04-28 16:47:12 -04:00
Heng Li 6420acca6d BED I/O 2019-04-28 16:47:12 -04:00
John Marshall 371bc9513a SAM TLEN should be 0 when either read is unmapped
this_rid/this_pos will be copied from r_prev(=r_next)'s values when this
read is unmapped (i.e., r is NULL). In this case, we can write RNEXT as
'=' but should not calculate TLEN from these placeholder values.
Similarly when the mate is unmapped (i.e., r_next is NULL).

Fixes #365.
2019-04-05 09:36:46 -04:00
Heng Li 169216bfff manpage was wrongly marked as "dirty" 2019-02-28 15:58:12 -05:00
Heng Li 6b391e3373 Release minimap2-2.16 (r922) 2019-02-28 15:49:24 -05:00
Heng Li 55e39c2d30 r921: output unmapped reads in full PAF 2019-02-27 15:03:19 -05:00
Kevin Chan 90b7b83ec7 fix typo in command line help 2019-02-27 14:46:57 -05:00
Heng Li d431dc0181 r917: added --max-chain-iter to avoid worst case
Resolves #324
2019-02-27 14:41:01 -05:00
Heng Li ccf1680aaf make it explicit that -x is preferred for prebuilt 2019-02-27 12:43:33 -05:00
Heng Li ea84fc0a53 r917: fixed a bug in command-line parsing
Resolves #344
2019-02-27 11:22:58 -05:00
Heng Li 19208fb06b r916: support long cs in sam-to-paf conversion 2019-02-17 09:35:23 -05:00
Heng Li e02bebd96d r915: fixed a bug caused by the latest change 2019-02-14 10:04:04 -05:00
Heng Li 32ab6ce15b r914: fixed two harmless division by 0
Resolves #326
2019-02-12 19:30:49 -05:00
Heng Li 1739a260fb r913: output tag "rl", length of unseedable regs 2019-02-05 14:19:17 -05:00
Heng Li aaf3233818 added mappy.Aligner.seq_names to return seq names
Resolves #312
2019-01-29 12:53:20 -05:00
Heng Li 8b05880f73 r911: option -o to output to file (#319) 2019-01-29 10:42:20 -05:00
Heng Li eba237f39d r910: meaningful error message (#320)
when minimap2 fails to create temporary files
2019-01-29 10:29:27 -05:00
Heng Li a8e1e3cbb8 updated citation with page numbers 2019-01-26 17:59:36 -05:00
Heng Li 597212b9f3 r908: added an assertion to detect a potential bug
as in #311
2019-01-23 11:18:50 -05:00
Heng Li 30abcf3cf9 r907: copy tag "cs" in sam2paf
Resolves #310
2019-01-13 17:52:31 -05:00
Heng Li 48e230f40d r906: de tag is wrongly calculated given "N"
Resolves #309
2019-01-11 19:39:09 -05:00
Heng Li c404f49569 Release minimap2-2.15 (r905) 2019-01-10 12:34:45 -05:00
Heng Li cf2bae6e9b r904: fixed a corner-case segfault. Resolves #307. 2019-01-10 09:57:05 -05:00
Heng Li 5b2fdfff9c r895: option in asmgene to count autosomal only 2018-12-14 10:36:47 -05:00
Heng Li ea2b1c5b2a r894: added --max-qlen to filter out long query 2018-12-12 12:27:32 -05:00
Heng Li eef1cee9b7 r893: added paftools.js vcfpair 2018-12-01 18:53:03 -05:00
Heng Li 2c52364527 r892: avoid de:f:0.0000 2018-11-24 21:54:28 -05:00
Heng Li 128476efc9 r891: compute gap-compressed divergence 2018-11-24 21:50:49 -05:00
Heng Li 1b3a6a0fe5 r890: removed "register" (#261) 2018-11-19 13:57:31 -05:00
Heng Li 83a8ee7038 r888: fixed incorrect CIGAR when --eqx in use
This was caused by mm_fix_cigar() which may change query/target offset in very
rare cases. Generating EQX has to beware of this change.

Resolves #266
2018-11-18 14:22:29 -05:00
Heng Li 62bbadf668 r887: fixed a bug in asmgene 2018-11-11 21:35:19 -05:00
Heng Li 91f548b497 r886: fixed two minor typos
Resolves #264
Resolves #265
2018-11-08 12:04:14 -05:00
Heng Li cdaf46665a r885: compute dup with asmstat 2018-11-07 00:26:05 -05:00
Heng Li 6596c63dcd r884: for C++ compatibility (#261) 2018-11-06 22:07:11 -05:00
Heng Li 59f23f7579 Release minimap2-2.14 (r883) 2018-11-06 00:03:16 -05:00
Heng Li 5e55e397e9 r882: guard against -E0 (#263) 2018-11-05 23:36:12 -05:00
Heng Li 88c421e8de r881: a recent change reduces sr accuracy 2018-11-05 22:03:59 -05:00
Heng Li 3db5bfe6e5 r880: fixed false wrong FASTA/Q alert 2018-11-05 20:52:07 -05:00
Heng Li 83dfdd5f50 draft release note 2018-11-05 20:07:57 -05:00
Heng Li 8a2b1cd4c9 updated mappy for extra option max_sw_mat 2018-11-05 19:28:44 -05:00
Heng Li 1ede8ca170 r877: renamed cap-sw-mat to cap-sw-mem 2018-11-05 11:46:38 -05:00
Heng Li 13981404e2 r876: skip DP if taking too much RAM (#259) 2018-11-05 11:43:10 -05:00
Heng Li fd64dd26f6 r875: warn given incorrect FASTA/Q
resolves #252
resolves #255
2018-11-05 10:02:44 -05:00
Heng Li 24df95e4b8 r874: don't call x86_simd() so often
This takes a few percent of time in profiler.
2018-11-05 09:20:35 -05:00
Heng Li a8ee48c2ce r873: comforming to C99/C11; resolves #261 2018-11-05 08:25:07 -05:00
Heng Li 09e089c3dc r872: choose the longest isoform 2018-11-04 23:48:50 -05:00
Heng Li e46cbb7d84 r871: print erroneous genes 2018-11-04 20:37:06 -05:00
Heng Li 57ec73ec6c r870: separate <50% and <10% 2018-11-04 19:31:25 -05:00
Heng Li 9e27575387 r869: classify incomplete genes 2018-11-04 19:21:55 -05:00
Heng Li b4ad8d8bf0 added asmgene
improvements coming; not made public yet
2018-11-04 17:24:05 -05:00
Heng Li e315b9fada hidden options to control bp calculation 2018-11-04 16:36:04 -05:00
Heng Li 42baf287a4 r866: fixed a typo; resolves #262 2018-10-30 09:11:55 -04:00
Heng Li 2ceba22a7a fixed a typo in manpage 2018-10-28 11:51:02 -04:00
Heng Li 9ed56b4a25 r860: MD/cs not working with --eqx 2018-10-26 23:23:53 -04:00
Heng Li ecb6c5c36c Document --no-pairing (#256) 2018-10-23 10:00:21 -04:00
Heng Li 377c7099a8 r858: fixed a bug; resolves #254 2018-10-22 22:47:11 -04:00
Heng Li 51e2abfa60 clarify that minimap2 may miss small exons 2018-10-22 11:16:16 -04:00
Heng Li 7b0a49732e r856: wrongly reported for an unrecognized option
Resolved #250
2018-10-19 20:07:14 -04:00
Heng Li 20268a6068 updated the copyright holder 2018-10-18 11:11:17 -04:00
Heng Li d04ac068fd r852: a minor when large --end-bonus is in use
We may use a large --end-bonus to mimic end-to-end alignment. In the short-read
mode, the candidate alignment region may be out of the band, which leads to
truncated alignment.
2018-10-15 21:28:27 -04:00
Heng Li 5d5d392c02 Release minimap2-2.13 (r850) 2018-10-11 13:18:31 -04:00
Heng Li 170863e553 r849: option -P doesn't work
I don't know why I haven't found it at the beginning.
2018-10-04 16:11:59 -04:00
Heng Li 97f97306a4 r847: guard against -N0 2018-09-27 15:13:44 -04:00
Heng Li 1077b7ddc8 r846: added --hard-mask-level for #244 2018-09-27 14:46:26 -04:00
Heng Li c57b59f02f r845: log peak memory 2018-09-23 20:27:49 -04:00
Torsten Seemann 34be359e25 Add -s sample option for VCF output 2018-09-19 18:24:47 -04:00
Heng Li 8b12da8b0f removed a useless dependency (not in repo) 2018-09-17 13:59:25 -04:00
Heng Li c63a33904f r836: fixed an integer overflow
Forgot this one.
2018-09-14 23:29:31 -04:00
Heng Li 70b0fede64 r835: improved help message. Resolved #232 2018-09-14 22:29:25 -04:00
Heng Li 0b681e51e7 Merge remote-tracking branch 'remotes/origin/master' 2018-09-14 22:22:20 -04:00
Heng Li 7d80d6de4a r832: fixed outdated -L. Resolved #231 and #233 2018-09-14 22:21:33 -04:00
Chris Rands 791e89ce0f PEP8 and other minor styles changes 2018-09-12 10:58:56 -04:00
Heng Li 98c48a1c45 Fixed wrong version links in the cookbook 2018-09-03 09:07:34 -04:00
Heng Li 63d397120a removed getopt.c from MANIFEST 2018-09-01 21:30:46 -04:00
Heng Li 7998fe9906 r829: replaced musl's getopt with ketopt 2018-09-01 21:18:02 -04:00
Heng Li 3a119d606f r828: --MD to support spliced alignment 2018-08-22 10:47:45 -04:00
Heng Li a5eafb75f9 Release minimap2-2.12 (r827) 2018-08-06 12:44:39 -04:00
Heng Li 9a567e4b37 allow mappy to change scoring 2018-08-06 09:52:13 -04:00
Heng Li 8e606bcc06 added a -C5 example to Getting Started 2018-08-06 09:08:33 -04:00
Heng Li a1b7219b5d explain added parameters 2018-08-05 21:32:05 -04:00
Heng Li b0f39a1a61 r823: mappy to index a single sequence 2018-08-05 20:57:05 -04:00
Heng Li 5ab6538757 r822: added option --no-end-flt 2018-08-05 19:42:12 -04:00
Heng Li b32296e18f r821: fixed memory when -y is used 2018-07-31 15:14:37 -04:00
Heng Li 99ecdf7b5d mappy to support arm64 (#203) 2018-07-24 23:53:02 -04:00
Heng Li ff9917a1c4 r819: mappy to support cs/MD 2018-07-24 23:29:55 -04:00
Mark Bicknell 8c064a5f29 Fixed mm_idx_is_idx to return the correct result on Windows. 2018-07-17 09:16:33 -04:00
Heng Li 0e137670fc Merge branch 'split' 2018-07-15 22:24:15 -04:00
Heng Li 395c8d678a r815: fixed a memory leak 2018-07-15 22:11:32 -04:00
Heng Li 830da7fa27 r814: resumed versioning 2018-07-15 11:48:14 -04:00
Heng Li a655cbef86 print SAM header; remove tmp files 2018-07-15 11:03:18 -04:00
Heng Li 4b707aac92 working with toy examples 2018-07-15 10:55:00 -04:00
Heng Li 951c0d1d35 apparently mm_append_cigar() wastes some memory 2018-07-14 23:47:44 -04:00
Heng Li 3545e35a42 pairing in the split-idx mode 2018-07-14 23:43:34 -04:00
Heng Li f3417da838 bugfix: unmapped records are duplicated in output 2018-07-14 22:54:05 -04:00
Heng Li e5277dbf5c code backup 2018-07-14 22:52:36 -04:00
Heng Li 1a55227d5a write hits to tmp files (unfinished) 2018-07-14 12:15:10 -04:00
Heng Li 5cfa621b2d use unmapped records 2018-07-07 12:49:15 -05:00
Heng Li a609a07f8c optionally output unmapped query in PAF 2018-07-07 10:26:08 -05:00
Heng Li bcf92b3c46 compute query coverage 2018-07-06 21:52:01 -05:00
Heng Li 097378ab90 reworked break point counting 2018-07-06 09:46:26 -04:00
Heng Li 10bbbe28c5 added asmstat 2018-07-05 13:22:32 -04:00
Hyeshik Chang c92a6866f3 Release the GIL to allow native Python threading. 2018-07-05 08:00:27 -04:00
Maël Kerbiriou 6908dc59a5 --splice implied when searching for splicing sites on single strand 2018-07-05 07:41:26 -04:00
Heng Li 50dae10421 paftools call to show statistics on longer indels 2018-07-03 14:28:09 -04:00
55 changed files with 4420 additions and 1228 deletions
+21
View File
@@ -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 }}
+3
View File
@@ -0,0 +1,3 @@
[submodule "lib/simde"]
path = lib/simde
url = https://github.com/nemequ/simde.git
+5 -1
View File
@@ -6,6 +6,10 @@ matrix:
- language: c
compiler: clang
script: make
- arch: arm64
language: c
compiler: gcc
script: make arm_neon=1 aarch64=1
- language: python
python: "2.7"
before_install: pip install cython
@@ -15,6 +19,6 @@ matrix:
before_install: pip install cython
script: python setup.py build_ext
- language: python
python: "3.6"
python: "3.9"
before_install: pip install cython
script: python setup.py build_ext
+46
View File
@@ -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.
+2 -1
View File
@@ -1,6 +1,7 @@
The MIT License
Copyright (c) 2017 Broad Institute, Inc.
Copyright (c) 2018- Dana-Farber Cancer Institute
2017-2018 Broad Institute, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+1 -2
View File
@@ -1,10 +1,9 @@
include *.h
include Makefile
include ksw2_dispatch.c
include getopt.c
include main.c
include README.md
include python/mappy.c
include sse2neon/emmintrin.h
include python/cmappy.h
include python/cmappy.pxd
include python/mappy.pyx
+33 -19
View File
@@ -1,7 +1,9 @@
CFLAGS= -g -Wall -O2 -Wc++-compat #-Wextra
CPPFLAGS= -DHAVE_KALLOC
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 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_EXTRA= sdust minimap2-lite
LIBS= -lm -lz -lpthread
@@ -22,6 +24,16 @@ else #if aarch64 is defined
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
@@ -32,8 +44,8 @@ all:$(PROG)
extra:all $(PROG_EXTRA)
minimap2:main.o getopt.o libminimap2.a
$(CC) $(CFLAGS) main.o getopt.o -o $@ -L. -lminimap2 $(LIBS)
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)
@@ -41,8 +53,8 @@ minimap2-lite:example.o libminimap2.a
libminimap2.a:$(OBJS)
$(AR) -csru $@ $(OBJS)
sdust:sdust.c getopt.o kalloc.o kalloc.h kdq.h kvec.h kseq.h sdust.h
$(CC) -D_SDUST_MAIN $(CFLAGS) $< getopt.o kalloc.o -o $@ -lz
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
# SSE-specific targets on x86/x86_64
@@ -93,26 +105,28 @@ depend:
# 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
chain.o: minimap.h mmpriv.h bseq.h kalloc.h
esterr.o: mmpriv.h minimap.h bseq.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
getopt.o: getopt.h
hit.o: mmpriv.h minimap.h bseq.h kalloc.h khash.h
index.o: kthread.h bseq.h minimap.h mmpriv.h kvec.h kalloc.h khash.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 getopt.h
map.o: kthread.h kvec.h kalloc.h sdust.h mmpriv.h minimap.h bseq.h khash.h
map.o: ksort.h
misc.o: mmpriv.h minimap.h bseq.h ksort.h
options.o: mmpriv.h minimap.h bseq.h
pe.o: mmpriv.h minimap.h bseq.h kvec.h kalloc.h ksort.h
lchain.o: mmpriv.h minimap.h bseq.h kseq.h kalloc.h krmq.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
sketch.o: kvec.h kalloc.h 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
+97
View File
@@ -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 chain.o align.o hit.o map.o format.o pe.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
+323
View File
@@ -1,3 +1,326 @@
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)
-----------------------------------
Changes to minimap2:
* Fixed wrongly formatted SAM when -L is in use (#231 and #233).
* Fixed an integer overflow in rare cases.
* Added --hard-mask-level to fine control split alignments (#244).
* Made --MD work with spliced alignment (#139).
* Replaced musl's getopt with ketopt for portability.
* Log peak memory usage on exit.
This release should produce alignments identical to v2.12 and v2.11.
(2.13: 11 October 2018, r850)
Release 2.12-r827 (6 August 2018)
---------------------------------
Changes to minimap2:
* Added option --split-prefix to write proper alignments (correct mapping
quality and clustered query sequences) given a multi-part index (#141 and
#189; mostly by @hasindu2008).
* Fixed a memory leak when option -y is in use.
Changes to mappy:
* Support the MD/cs tag (#183 and #203).
* Allow mappy to index a single sequence, to add extra flags and to change the
scoring system.
Minimap2 should produce alignments identical to v2.11.
(2.12: 6 August 2018, r827)
Release 2.11-r797 (20 June 2018)
--------------------------------
+49 -19
View File
@@ -1,7 +1,7 @@
[![GitHub Downloads](https://img.shields.io/github/downloads/lh3/minimap2/total.svg?style=social&logo=github&label=Download)](https://github.com/lh3/minimap2/releases)
[![BioConda Install](https://img.shields.io/conda/dn/bioconda/minimap2.svg?style=flag&label=BioConda%20install)](https://anaconda.org/bioconda/minimap2)
[![PyPI](https://img.shields.io/pypi/v/mappy.svg?style=flat)](https://pypi.python.org/pypi/mappy)
[![Build Status](https://travis-ci.org/lh3/minimap2.svg?branch=master)](https://travis-ci.org/lh3/minimap2)
[![Build Status](https://github.com/lh3/minimap2/actions/workflows/ci.yaml/badge.svg)](https://github.com/lh3/minimap2/actions)
## <a name="started"></a>Getting Started
```sh
git clone https://github.com/lh3/minimap2
@@ -9,20 +9,25 @@ cd minimap2 && make
# long sequences against a reference genome
./minimap2 -a test/MT-human.fa test/MT-orang.fa > test.sam
# create an index first and then map
./minimap2 -d MT-human.mmi test/MT-human.fa
./minimap2 -a MT-human.mmi test/MT-orang.fa > test.sam
./minimap2 -x map-ont -d MT-human-ont.mmi test/MT-human.fa
./minimap2 -a MT-human-ont.mmi test/MT-orang.fa > test.sam
# 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-hifi ref.fa pacbio-ccs.fq.gz > aln.sam # PacBio HiFi/CCS genomic reads (v2.19 or lateer)
./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 splice ref.fa rna-reads.fa > aln.sam # spliced long reads
./minimap2 -ax splice -k14 -uf ref.fa reads.fa > aln.sam # Nanopore Direct RNA-seq
./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: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 -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
# man page for detailed command line options
man ./minimap2.1
```
## Table of Contents
- [Getting Started](#started)
@@ -69,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
the [release page][release] with:
```sh
curl -L https://github.com/lh3/minimap2/releases/download/v2.11/minimap2-2.11_x64-linux.tar.bz2 | tar -jxvf -
./minimap2-2.11_x64-linux/minimap2
curl -L https://github.com/lh3/minimap2/releases/download/v2.20/minimap2-2.20_x64-linux.tar.bz2 | tar -jxvf -
./minimap2-2.20_x64-linux/minimap2
```
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
@@ -78,7 +83,14 @@ directory to compile. If you see compilation errors, try `make sse2only=1`
to disable SSE4 code, which will make minimap2 slightly slower.
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
@@ -125,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
```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
```
The difference between `map-pb` and `map-ont` is that `map-pb` uses
homopolymer-compressed (HPC) minimizers as seeds, while `map-ont` uses ordinary
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.
#### <a name="map-long-splice"></a>Map long mRNA/cDNA reads
```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 -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
@@ -176,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
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
```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
```
Similarly, `ava-pb` uses HPC minimizers while `ava-ont` uses ordinary
@@ -226,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
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
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`.
**TL;DR**: if you work with ultra-long reads and use tools that only process
@@ -247,7 +272,7 @@ CGATCGATAAATAGAGTAG---GAATAGCA
CGATCG---AATAGAGTAGGTCGAATtGCA
```
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
similar to the `MD` SAM tag but is standalone and easier to parse.
@@ -313,16 +338,17 @@ highlighted in bold. The description may help to tune minimap2 parameters.
### <a name="help"></a>Getting help
Manpage [minimap2.1][manpage] provides detailed description of minimap2
command line options and optional tags. If you encounter bugs or have further
questions or requests, you can raise an issue at the [issue page][issue].
There is not a specific mailing list for the time being.
command line options and optional tags. The [FAQ](FAQ.md) page answers several
frequently asked questions. If you encounter bugs or have further questions or
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
If you use minimap2 in your work, please cite:
> 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
@@ -353,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
sequences can well exceed this threshold.
* Minimap2 often misses small exons.
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
@@ -371,3 +399,5 @@ mappy` or [from BioConda][mappyconda] via `conda install -c bioconda mappy`.
[manpage]: https://lh3.github.io/minimap2/minimap2.html
[manpage-cs]: https://lh3.github.io/minimap2/minimap2.html#10
[doi]: https://doi.org/10.1093/bioinformatics/bty191
[smide]: https://github.com/nemequ/simde
[unimap]: https://github.com/lh3/unimap
+136 -97
View File
@@ -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;
if (z > *max_zdrop) {
*max_zdrop = z;
pos[0][0] = *max_i, pos[0][1] = i + 1;
pos[1][0] = *max_j, pos[1][1] = j + 1;
pos[0][0] = *max_i, pos[0][1] = i;
pos[1][0] = *max_j, pos[1][1] = j;
}
} else *max = score, *max_i = i, *max_j = j;
}
@@ -123,6 +123,25 @@ static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq,
}
}
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
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 == 1 || op == 2 || 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|1;
p->cigar[k+1] = s[2]<<4|2;
for (k += 2; k < l; ++k)
p->cigar[k] &= 0xf;
to_shrink = 1;
}
k = l;
}
}
if (to_shrink) { // squeeze out zero-length operations
int32_t l = 0;
for (k = 0; k < p->n_cigar; ++k) // squeeze out zero-length operations
@@ -147,78 +166,6 @@ static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq,
}
}
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)
{
uint32_t k, l;
int32_t s = 0, max = 0, qshift, tshift, toff = 0, qoff = 0;
mm_extra_t *p = r->p;
if (p == 0) return;
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
r->blen = r->mlen = 0;
for (k = 0; k < p->n_cigar; ++k) {
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
if (op == 0) { // match/mismatch
int n_ambi = 0, n_diff = 0;
for (l = 0; l < len; ++l) {
int cq = qseq[qoff + l], ct = tseq[toff + l];
if (ct > 3 || cq > 3) ++n_ambi;
else if (ct != cq) ++n_diff;
s += mat[ct * 5 + cq];
if (s < 0) s = 0;
else max = max > s? max : s;
}
r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
toff += len, qoff += len;
} else if (op == 1) { // insertion
int n_ambi = 0;
for (l = 0; l < len; ++l)
if (qseq[qoff + l] > 3) ++n_ambi;
r->blen += len - n_ambi, p->n_ambi += n_ambi;
s -= q + e * len;
if (s < 0) s = 0;
qoff += len;
} else if (op == 2) { // deletion
int n_ambi = 0;
for (l = 0; l < len; ++l)
if (tseq[toff + l] > 3) ++n_ambi;
r->blen += len - n_ambi, p->n_ambi += n_ambi;
s -= q + e * len;
if (s < 0) s = 0;
toff += len;
} else if (op == 3) { // intron
toff += len;
}
}
p->dp_max = max;
assert(qoff == r->qe - r->qs && toff == r->re - r->rs);
}
static void mm_append_cigar(mm_reg1_t *r, uint32_t n_cigar, uint32_t *cigar) // TODO: this calls the libc realloc()
{
mm_extra_t *p;
if (n_cigar == 0) return;
if (r->p == 0) {
uint32_t capacity = n_cigar + sizeof(mm_extra_t); // TODO: should this be "n_cigar + sizeof(mm_extra_t)/4" instead?
kroundup32(capacity);
r->p = (mm_extra_t*)calloc(capacity, 4);
r->p->capacity = capacity;
} else if (r->p->n_cigar + n_cigar + sizeof(mm_extra_t) > r->p->capacity) {
r->p->capacity = r->p->n_cigar + n_cigar + sizeof(mm_extra_t);
kroundup32(r->p->capacity);
r->p = (mm_extra_t*)realloc(r->p, r->p->capacity * 4);
}
p = r->p;
if (p->n_cigar > 0 && (p->cigar[p->n_cigar-1]&0xf) == (cigar[0]&0xf)) { // same CIGAR op at the boundary
p->cigar[p->n_cigar-1] += cigar[0]>>4<<4;
if (n_cigar > 1) memcpy(p->cigar + p->n_cigar, cigar + 1, (n_cigar - 1) * 4);
p->n_cigar += n_cigar - 1;
} else {
memcpy(p->cigar + p->n_cigar, cigar, n_cigar * 4);
p->n_cigar += n_cigar;
}
}
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;
@@ -290,7 +237,80 @@ static void mm_update_cigar_eqx(mm_reg1_t *r, const uint8_t *qseq, const uint8_t
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 *mat, int w, int end_bonus, int zdrop, int flag, ksw_extz_t *ez)
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)
{
uint32_t k, l;
int32_t s = 0, max = 0, qshift, tshift, toff = 0, qoff = 0;
mm_extra_t *p = r->p;
if (p == 0) return;
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
r->blen = r->mlen = 0;
for (k = 0; k < p->n_cigar; ++k) {
uint32_t op = p->cigar[k]&0xf, len = p->cigar[k]>>4;
if (op == 0) { // match/mismatch
int n_ambi = 0, n_diff = 0;
for (l = 0; l < len; ++l) {
int cq = qseq[qoff + l], ct = tseq[toff + l];
if (ct > 3 || cq > 3) ++n_ambi;
else if (ct != cq) ++n_diff;
s += mat[ct * 5 + cq];
if (s < 0) s = 0;
else max = max > s? max : s;
}
r->blen += len - n_ambi, r->mlen += len - (n_ambi + n_diff), p->n_ambi += n_ambi;
toff += len, qoff += len;
} else if (op == 1) { // insertion
int n_ambi = 0;
for (l = 0; l < len; ++l)
if (qseq[qoff + l] > 3) ++n_ambi;
r->blen += len - n_ambi, p->n_ambi += n_ambi;
s -= q + e * len;
if (s < 0) s = 0;
qoff += len;
} else if (op == 2) { // deletion
int n_ambi = 0;
for (l = 0; l < len; ++l)
if (tseq[toff + l] > 3) ++n_ambi;
r->blen += len - n_ambi, p->n_ambi += n_ambi;
s -= q + e * len;
if (s < 0) s = 0;
toff += len;
} else if (op == 3) { // intron
toff += len;
}
}
p->dp_max = max;
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()
{
mm_extra_t *p;
if (n_cigar == 0) return;
if (r->p == 0) {
uint32_t capacity = n_cigar + sizeof(mm_extra_t)/4;
kroundup32(capacity);
r->p = (mm_extra_t*)calloc(capacity, 4);
r->p->capacity = capacity;
} else if (r->p->n_cigar + n_cigar + sizeof(mm_extra_t)/4 > r->p->capacity) {
r->p->capacity = r->p->n_cigar + n_cigar + sizeof(mm_extra_t)/4;
kroundup32(r->p->capacity);
r->p = (mm_extra_t*)realloc(r->p, r->p->capacity * 4);
}
p = r->p;
if (p->n_cigar > 0 && (p->cigar[p->n_cigar-1]&0xf) == (cigar[0]&0xf)) { // same CIGAR op at the boundary
p->cigar[p->n_cigar-1] += cigar[0]>>4<<4;
if (n_cigar > 1) memcpy(p->cigar + p->n_cigar, cigar + 1, (n_cigar - 1) * 4);
p->n_cigar += n_cigar - 1;
} else {
memcpy(p->cigar + p->n_cigar, cigar, n_cigar * 4);
p->n_cigar += n_cigar;
}
}
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)
{
if (mm_dbg_flag & MM_DBG_PRINT_ALN_SEQ) {
int i;
@@ -300,8 +320,11 @@ 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);
fputc('\n', stderr);
}
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, flag, ez);
if (opt->max_sw_mat > 0 && (int64_t)tlen * qlen > opt->max_sw_mat) {
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)
ksw_extz2_sse(km, qlen, qseq, tlen, tseq, 5, mat, opt->q, opt->e, w, zdrop, end_bonus, flag, ez);
else
@@ -414,7 +437,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);
q_span_pre = a[as1 + j - 1].y >> 32 & 0xff;
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;
gap2 = gap2 > 0? gap2 : -gap2;
if (m > gap1 + gap2) break;
@@ -543,8 +566,8 @@ 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);
int32_t rid = a[r->as].x<<1>>33, rev = a[r->as].x>>63, as1, cnt1;
uint8_t *tseq, *qseq;
int32_t i, l, bw, dropped = 0, extra_flag = 0, rs0, re0, qs0, qe0;
uint8_t *tseq, *qseq, *junc;
int32_t i, l, bw, bw_long, dropped = 0, extra_flag = 0, rs0, re0, qs0, qe0;
int32_t rs, re, qs, qe;
int32_t rs1, qs1, re1, qe1;
int8_t mat[25];
@@ -555,6 +578,8 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
if (r->cnt == 0) return;
ksw_gen_simple_mat(5, mat, opt->a, opt->b, opt->sc_ambi);
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)) {
mm_max_stretch(r, a, &as1, &cnt1);
@@ -563,11 +588,12 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
re = (int32_t)a[as1+cnt1-1].x + 1;
qe = (int32_t)a[as1+cnt1-1].y + 1;
} else {
if (is_splice) {
mm_fix_bad_ends_splice(km, opt, mi, r, mat, qlen, qseq0, a, &as1, &cnt1);
} else {
mm_fix_bad_ends(r, a, opt->bw, opt->min_chain_score * 2, &as1, &cnt1);
}
if (!(opt->flag & MM_F_NO_END_FLT)) {
if (is_splice)
mm_fix_bad_ends_splice(km, opt, mi, r, mat, qlen, qseq0, a, &as1, &cnt1);
else
mm_fix_bad_ends(r, a, opt->bw, opt->min_chain_score * 2, &as1, &cnt1);
} else as1 = r->as, cnt1 = r->cnt;
mm_filter_bad_seeds(km, as1, cnt1, a, 10, 40, opt->max_gap>>1, 10);
mm_filter_bad_seeds_alt(km, as1, cnt1, a, 30, opt->max_gap>>1);
mm_adjust_minier(mi, qseq0, &a[as1], &rs, &qs);
@@ -608,6 +634,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
if (++l > opt->min_cnt) {
l = rs0 - x > qs0 - y? rs0 - x : qs0 - y;
rs1 = rs0 - l, qs1 = qs0 - l;
if (rs1 < 0) rs1 = 0; // not strictly necessary; better have this guard for explicit
break;
}
}
@@ -621,6 +648,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
l = l < rs? l : rs;
rs1 = rs1 > rs - l? rs1 : rs - l;
rs0 = rs0 < rs1? rs0 : rs1;
rs0 = rs0 < rs? rs0 : rs;
} else rs0 = rs, qs0 = qs;
// compute re0 and qe0
re0 = (int32_t)a[r->as + r->cnt - 1].x + 1;
@@ -659,13 +687,16 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
assert(re0 > rs0);
tseq = (uint8_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];
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(rs - rs0, tseq);
mm_align_pair(km, opt, qs - qs0, qseq, rs - rs0, tseq, 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) {
mm_append_cigar(r, ez->n_cigar, ez->cigar);
r->p->dp_score += ez->max;
@@ -685,12 +716,13 @@ 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);
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)) {
int j, bw1 = bw, zdrop_code;
int j, bw1 = bw_long, zdrop_code;
if (a[as1+i].y & MM_SEED_LONG_JOIN)
bw1 = qe - qs > re - rs? qe - qs : re - rs;
// perform alignment
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
assert(qe - qs == re - rs);
ksw_reset_extz(ez);
@@ -700,15 +732,22 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
}
ez->cigar = ksw_push_cigar(km, &ez->n_cigar, &ez->m_cigar, ez->cigar, 0, qe - qs);
} else { // perform normal gapped alignment
mm_align_pair(km, opt, qe - qs, qseq, re - rs, tseq, 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
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, 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
if (ez->n_cigar > 0)
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 (!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)
if ((int32_t)a[as1 + j].x <= rs + ez->max_t)
break;
@@ -730,7 +769,8 @@ 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
qseq = &qseq0[rev][qe];
mm_idx_getseq(mi, rid, re, re0, tseq);
mm_align_pair(km, opt, qe0 - qe, qseq, re0 - re, tseq, mat, bw, opt->end_bonus, opt->zdrop, extra_flag|KSW_EZ_EXTZ_ONLY, ez);
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) {
mm_append_cigar(r, ez->n_cigar, ez->cigar);
r->p->dp_score += ez->max;
@@ -747,13 +787,13 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
assert(re1 - rs1 <= re0 - rs0);
if (r->p) {
mm_idx_getseq(mi, rid, rs1, re1, tseq);
mm_update_extra(r, &qseq0[r->rev][qs1], tseq, mat, opt->q, opt->e);
if (opt->flag & MM_F_EQX) mm_update_cigar_eqx(r, &qseq0[r->rev][qs1], tseq);
mm_update_extra(r, &qseq0[r->rev][qs1], tseq, mat, opt->q, opt->e, opt->flag & MM_F_EQX);
if (rev && r->p->trans_strand)
r->p->trans_strand ^= 3; // flip to the read strand
}
kfree(km, tseq);
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)
@@ -787,7 +827,7 @@ static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, i
mm_seq_rev(tl, tseq);
if (score < opt->min_dp_max) goto end_align1_inv;
q_off = ql - (q_off + 1), t_off = tl - (t_off + 1);
mm_align_pair(km, opt, ql - q_off, qseq + q_off, tl - t_off, tseq + t_off, mat, (int)(opt->bw * 1.5), -1, opt->zdrop, KSW_EZ_EXTZ_ONLY, ez);
mm_align_pair(km, opt, ql - q_off, qseq + q_off, tl - t_off, tseq + t_off, 0, mat, (int)(opt->bw * 1.5), -1, opt->zdrop, KSW_EZ_EXTZ_ONLY, ez);
if (ez->n_cigar == 0) goto end_align1_inv; // should never be here
mm_append_cigar(r_inv, ez->n_cigar, ez->cigar);
r_inv->p->dp_score = ez->max;
@@ -806,8 +846,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->re = r_inv->rs + ez->max_t + 1;
mm_update_extra(r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e);
if (opt->flag & MM_F_EQX) mm_update_cigar_eqx(r_inv, &qseq[q_off], &tseq[t_off]);
mm_update_extra(r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e, opt->flag & MM_F_EQX);
ret = 1;
end_align1_inv:
kfree(km, tseq);
@@ -878,6 +917,6 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
kfree(km, qseq0[0]);
kfree(km, ez.cigar);
mm_filter_regs(opt, qlen, n_regs_, regs);
mm_hit_sort_by_dp(km, n_regs_, regs);
mm_hit_sort(km, n_regs_, regs, opt->alt_drop);
return regs;
}
+16 -9
View File
@@ -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,
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,
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,
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,
@@ -39,7 +39,7 @@ mm_bseq_file_t *mm_bseq_open(const char *fn)
{
mm_bseq_file_t *fp;
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;
fp = (mm_bseq_file_t*)calloc(1, sizeof(mm_bseq_file_t));
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)
{
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->seq = kstrdup(&ks->seq);
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;
}
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;
int ret;
kvec_t(mm_bseq1_t) a = {0,0,0};
kseq_t *ks = fp->ks;
*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;
memset(&fp->s, 0, sizeof(mm_bseq1_t));
}
while (kseq_read(ks) >= 0) {
while ((ret = kseq_read(ks)) >= 0) {
mm_bseq1_t *s;
assert(ks->seq.l <= INT32_MAX);
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;
if (size >= chunk_size) {
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);
if (mm_qname_same(fp->s.name, a.a[a.n-1].name)) {
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;
}
}
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;
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_);
}
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_);
}
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;
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;
}
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_);
}
+5 -5
View File
@@ -18,11 +18,11 @@ typedef struct {
mm_bseq_file_t *mm_bseq_open(const char *fn);
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_read2(mm_bseq_file_t *fp, int 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_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_frag(int n_fp, mm_bseq_file_t **fp, int chunk_size, int with_qual, 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, int64_t chunk_size, int with_qual, int frag_mode, 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, 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, int64_t chunk_size, int with_qual, int *n_);
int mm_bseq_eof(mm_bseq_file_t *fp);
extern unsigned char seq_nt4_table[256];
-157
View File
@@ -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;
}
+30
View File
@@ -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
View File
@@ -24,18 +24,18 @@
This cookbook walks you through a variety of applications of minimap2 and its
companion script `paftools.js`. All data here are freely available from the
minimap2 release page at version tag [v2.11][v2.11]. Some examples only work
with v2.11 or later.
minimap2 release page at version tag [v2.10][v2.10]. Some examples only work
with v2.10 or later.
To acquire the data used in this cookbook and to install minimap2 and paftools,
please follow the command lines below:
```sh
# install minimap2 executables
curl -L https://github.com/lh3/minimap2/releases/download/v2.11/minimap2-2.11_x64-linux.tar.bz2 | tar jxf -
cp minimap2-2.11_x64-linux/{minimap2,k8,paftools.js} . # copy executables
curl -L https://github.com/lh3/minimap2/releases/download/v2.20/minimap2-2.20_x64-linux.tar.bz2 | tar jxf -
cp minimap2-2.20_x64-linux/{minimap2,k8,paftools.js} . # copy executables
export PATH="$PATH:"`pwd` # put the current directory on PATH
# download example datasets
curl -L https://github.com/lh3/minimap2/releases/download/v2.11/cookbook-data.tgz | tar zxf -
curl -L https://github.com/lh3/minimap2/releases/download/v2.10/cookbook-data.tgz | tar zxf -
```
## <a name="map-reads"></a>Mapping Genomic Reads
@@ -240,4 +240,4 @@ with `-x ava-pb` (99% vs 93% with `-x ava-ont`).
[pbsim]: https://github.com/pfaucon/PBSIM-PacBio-Simulator
[mason2]: https://github.com/seqan/seqan/tree/master/apps/mason2
[paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
[v2.11]: https://github.com/lh3/minimap2/releases/tag/v2.11
[v2.10]: https://github.com/lh3/minimap2/releases/tag/v2.10
+1 -1
View File
@@ -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;
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;
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));
}
}
+3 -1
View File
@@ -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
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
gzrewind(f);
kseq_rewind(ks);
while (kseq_read(ks) >= 0) { // each kseq_read() call reads one query sequence
mm_reg1_t *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%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!
printf("%d%c", r->p->cigar[i]>>4, "MIDSHN"[r->p->cigar[i]&0xf]);
printf("%d%c", r->p->cigar[i]>>4, "MIDNSH"[r->p->cigar[i]&0xf]);
putchar('\n');
free(r->p);
}
+102 -33
View File
@@ -79,11 +79,11 @@ static char *mm_escape(char *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;
memset(mm_rg_id, 0, 256);
if (s == 0) return;
if (s == 0) return 0;
if (strstr(s, "@RG") != s) {
if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line is not started with @RG\n");
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");
goto err_set_rg;
}
rg_line = strdup(s);
rg_line = (char*)malloc(strlen(s) + 1);
strcpy(rg_line, s);
mm_escape(rg_line);
if ((p = strstr(rg_line, "\tID:")) == 0) {
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)
*r++ = *q;
mm_sprintf_lite(str, "%s\n", rg_line);
return 0;
err_set_rg:
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};
int ret = 0;
if (idx) {
uint32_t 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);
}
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");
if (ver) mm_sprintf_lite(&str, "\tVN:%s", ver);
if (argc > 1) {
@@ -131,16 +135,17 @@ void mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int
}
mm_err_puts(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)
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)
{
int i, q_off, t_off;
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) {
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
assert(op >= 0 && op <= 3);
if (op == 0) { // match
assert((op >= 0 && op <= 3) || op == 7 || op == 8);
if (op == 0 || op == 7 || op == 8) { // match
int l_tmp = 0;
for (j = 0; j < len; ++j) {
if (qseq[q_off + j] != tseq[t_off + j]) {
@@ -181,14 +186,14 @@ static void write_cs_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);
}
static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mm_reg1_t *r, char *tmp)
static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mm_reg1_t *r, char *tmp, int write_tag)
{
int i, q_off, t_off, l_MD = 0;
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) {
int j, op = r->p->cigar[i]&0xf, len = r->p->cigar[i]>>4;
assert(op >= 0 && op <= 2); // introns (aka reference skips) are not supported
if (op == 0) { // match
assert((op >= 0 && op <= 3) || op == 7 || op == 8);
if (op == 0 || op == 7 || op == 8) { // match
for (j = 0; j < len; ++j) {
if (qseq[q_off + j] != tseq[t_off + j]) {
mm_sprintf_lite(s, "%d%c", l_MD, "ACGTN"[tseq[t_off + j]]);
@@ -204,13 +209,15 @@ static void write_MD_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq
mm_sprintf_lite(s, "%d^%s", l_MD, tmp);
l_MD = 0;
t_off += len;
} else if (op == 3) { // reference skip
t_off += len;
}
}
if (l_MD > 0) mm_sprintf_lite(s, "%d", l_MD);
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)
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)
{
extern unsigned char seq_nt4_table[256];
int i;
@@ -230,11 +237,46 @@ static void write_cs_or_MD(void *km, kstring_t *s, const mm_idx_t *mi, const mm_
qseq[r->qe - i - 1] = c >= 4? 4 : 3 - c;
}
}
if (is_MD) write_MD_core(s, tseq, qseq, r, tmp);
else write_cs_core(s, tseq, qseq, r, tmp, no_iden);
if (is_MD) write_MD_core(s, tseq, qseq, r, tmp, write_tag);
else write_cs_core(s, tseq, qseq, r, tmp, no_iden, write_tag);
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)
{
mm_bseq1_t t;
kstring_t str;
str.s = *buf, str.l = 0, str.m = *max_len;
t.l_seq = strlen(seq);
t.seq = (char*)seq;
write_cs_or_MD(km, &str, mi, &t, r, no_iden, is_MD, 0);
*max_len = str.m;
*buf = str.s;
return str.l;
}
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);
}
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);
}
double mm_event_identity(const mm_reg1_t *r)
{
int32_t i, n_gapo = 0, n_gap = 0;
if (r->p == 0) return -1.0f;
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 == 1 || op == 2)
++n_gapo, n_gap += len;
}
return (double)r->mlen / (r->blen + r->p->n_ambi - n_gap + n_gapo);
}
static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
{
int type;
@@ -247,18 +289,30 @@ 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);
if (r->parent == r->id) mm_sprintf_lite(s, "\ts2:i:%d", r->subsc);
if (r->div >= 0.0f && r->div <= 1.0f) {
char buf[8];
if (r->p) {
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;
else sprintf(buf, "%.4f", r->div);
else snprintf(buf, 16, "%.4f", r->div);
mm_sprintf_lite(s, "\tdv:f:%s", buf);
}
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, int opt_flag, int rep_len)
{
s->l = 0;
if (r == 0) {
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;
}
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);
else mm_sprintf_lite(s, "%d", r->rid);
@@ -266,6 +320,7 @@ void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const m
mm_sprintf_lite(s, "\t%d\t%d", r->mlen, r->blen);
mm_sprintf_lite(s, "\t%d", r->mapq);
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)) {
uint32_t k;
mm_sprintf_lite(s, "\tcg:Z:");
@@ -273,11 +328,16 @@ void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const m
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, "MIDNSHP=XB"[r->p->cigar[k]&0xf]);
}
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);
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&MM_F_OUT_MD, 1);
if ((opt_flag & MM_F_COPY_COMMENT) && 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, int 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)
{
extern unsigned char seq_comp_table[256];
@@ -319,6 +379,7 @@ 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);
} else {
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);
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]);
@@ -327,11 +388,11 @@ static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, co
}
}
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, int opt_flag, int rep_len)
{
const int max_bam_cigar_op = 65535;
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 *r = n_regs > 0 && reg_idx < n_regs && reg_idx >= 0? &regs[reg_idx] : NULL;
@@ -380,7 +441,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);
} else mm_sprintf_lite(s, "\t*\t0\t0\t*");
} 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);
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;
@@ -390,9 +451,11 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
cigar_in_tag = 1;
}
if (cigar_in_tag) {
if (flag & 0x100) mm_sprintf_lite(s, "0S"); // secondary alignment
else if (flag & 0x800) mm_sprintf_lite(s, "%dS", r->re - r->rs); // supplementary alignment
else mm_sprintf_lite(s, "%dS", t->l_seq);
int slen;
if ((flag & 0x900) == 0 || (opt_flag & MM_F_SOFTCLIP)) slen = t->l_seq;
else if (flag & 0x100) slen = 0;
else slen = r->qe - r->qs;
mm_sprintf_lite(s, "%dS%dN", slen, r->re - r->rs);
} else write_sam_cigar(s, flag, 0, t->l_seq, r, opt_flag);
}
@@ -401,17 +464,17 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
int tlen = 0;
if (this_rid >= 0 && r_next) {
if (this_rid == r_next->rid) {
int this_pos5 = r && r->rev? r->re - 1 : this_pos;
int next_pos5 = r_next->rev? r_next->re - 1 : r_next->rs;
tlen = next_pos5 - this_pos5;
if (r) {
int this_pos5 = r->rev? r->re - 1 : this_pos;
int next_pos5 = r_next->rev? r_next->re - 1 : r_next->rs;
tlen = next_pos5 - this_pos5;
}
mm_sprintf_lite(s, "\t=\t");
} else mm_sprintf_lite(s, "\t%s\t", mi->seq[r_next->rid].name);
mm_sprintf_lite(s, "%d\t", r_next->rs + 1);
} 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);
} 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
} else mm_sprintf_lite(s, "\t*\t0\t"); // neither has coordinates
if (tlen > 0) ++tlen;
@@ -472,10 +535,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)))
write_cs_or_MD(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG), opt_flag&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);
if (cigar_in_tag)
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)
mm_sprintf_lite(s, "\t%s", t->comment);
@@ -483,6 +547,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)
}
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)
{
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)
{
int i;
-216
View File
@@ -1,216 +0,0 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "getopt.h"
char *optarg;
int optind=1, opterr=1, optopt, __optpos, optreset=0;
#define optpos __optpos
static void __getopt_msg(const char *a, const char *b, const char *c, size_t l)
{
FILE *f = stderr;
#if !defined(WIN32) && !defined(_WIN32)
flockfile(f);
#endif
fputs(a, f);
fwrite(b, strlen(b), 1, f);
fwrite(c, 1, l, f);
fputc('\n', f);
#if !defined(WIN32) && !defined(_WIN32)
funlockfile(f);
#endif
}
int getopt(int argc, char * const argv[], const char *optstring)
{
int i, c, d;
int k, l;
char *optchar;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind])
return -1;
if (argv[optind][0] != '-') {
if (optstring[0] == '-') {
optarg = argv[optind++];
return 1;
}
return -1;
}
if (!argv[optind][1])
return -1;
if (argv[optind][1] == '-' && !argv[optind][2])
return optind++, -1;
if (!optpos) optpos++;
c = argv[optind][optpos], k = 1;
optchar = argv[optind]+optpos;
optopt = c;
optpos += k;
if (!argv[optind][optpos]) {
optind++;
optpos = 0;
}
if (optstring[0] == '-' || optstring[0] == '+')
optstring++;
i = 0;
d = 0;
do {
d = optstring[i], l = 1;
if (l>0) i+=l; else i++;
} while (l && d != c);
if (d != c) {
if (optstring[0] != ':' && opterr)
__getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
return '?';
}
if (optstring[i] == ':') {
if (optstring[i+1] == ':') optarg = 0;
else if (optind >= argc) {
if (optstring[0] == ':') return ':';
if (opterr) __getopt_msg(argv[0],
": option requires an argument: ",
optchar, k);
return '?';
}
if (optstring[i+1] != ':' || optpos) {
optarg = argv[optind++] + optpos;
optpos = 0;
}
}
return c;
}
static void permute(char *const *argv, int dest, int src)
{
char **av = (char **)argv;
char *tmp = av[src];
int i;
for (i=src; i>dest; i--)
av[i] = av[i-1];
av[dest] = tmp;
}
static int __getopt_long_core(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
optarg = 0;
if (longopts && argv[optind][0] == '-' &&
((longonly && argv[optind][1] && argv[optind][1] != '-') ||
(argv[optind][1] == '-' && argv[optind][2])))
{
int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
int i, cnt, match = -1;
char *opt;
for (cnt=i=0; longopts[i].name; i++) {
const char *name = longopts[i].name;
opt = argv[optind]+1;
if (*opt == '-') opt++;
for (; *name && *name == *opt; name++, opt++);
if (*opt && *opt != '=') continue;
match = i;
if (!*name) {
cnt = 1;
break;
}
cnt++;
}
if (cnt==1) {
i = match;
optind++;
optopt = longopts[i].val;
if (*opt == '=') {
if (!longopts[i].has_arg) {
if (colon || !opterr)
return '?';
__getopt_msg(argv[0],
": option does not take an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optarg = opt+1;
} else if (longopts[i].has_arg == required_argument) {
if (!(optarg = argv[optind])) {
if (colon) return ':';
if (!opterr) return '?';
__getopt_msg(argv[0],
": option requires an argument: ",
longopts[i].name,
strlen(longopts[i].name));
return '?';
}
optind++;
}
if (idx) *idx = i;
if (longopts[i].flag) {
*longopts[i].flag = longopts[i].val;
return 0;
}
return longopts[i].val;
}
if (argv[optind][1] == '-') {
if (!colon && opterr)
__getopt_msg(argv[0], cnt ?
": option is ambiguous: " :
": unrecognized option: ",
argv[optind]+2,
strlen(argv[optind]+2));
optind++;
return '?';
}
}
return getopt(argc, argv, optstring);
}
static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
{
int ret, skipped, resumed;
if (!optind || optreset) {
optreset = 0;
__optpos = 0;
optind = 1;
}
if (optind >= argc || !argv[optind]) return -1;
skipped = optind;
if (optstring[0] != '+' && optstring[0] != '-') {
int i;
for (i=optind; ; i++) {
if (i >= argc || !argv[i]) return -1;
if (argv[i][0] == '-' && argv[i][1]) break;
}
optind = i;
}
resumed = optind;
ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
if (resumed > skipped) {
int i, cnt = optind-resumed;
for (i=0; i<cnt; i++)
permute(argv, skipped, optind-1);
optind = skipped + cnt;
}
return ret;
}
int getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 0);
}
int getopt_long_only(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx)
{
return __getopt_long(argc, argv, optstring, longopts, idx, 1);
}
-53
View File
@@ -1,53 +0,0 @@
/*
Copyright 2005-2014 Rich Felker, et al.
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.
*/
#ifndef _GETOPT_H
#define _GETOPT_H
#ifdef __cplusplus
extern "C" {
#endif
int getopt(int, char * const [], const char *);
extern char *optarg;
extern int optind, opterr, optopt, optreset;
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
int getopt_long(int, char *const *, const char *, const struct option *, int *);
int getopt_long_only(int, char *const *, const char *, const struct option *, int *);
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#ifdef __cplusplus
}
#endif
#endif
+35 -67
View File
@@ -87,6 +87,22 @@ mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u,
return r;
}
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)
{
if (n <= 0 || n >= r->cnt) return;
@@ -106,7 +122,7 @@ void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a)
r->split |= 1, r2->split |= 2;
}
void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff) // 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;
uint64_t *cov;
@@ -118,6 +134,7 @@ void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff
for (i = 1, k = 1; i < n; ++i) {
mm_reg1_t *ri = &r[i];
int si = ri->qs, ei = ri->qe, n_cov = 0, uncov_len = 0;
if (hard_mask_level) goto skip_uncov;
for (j = 0; j < k; ++j) { // traverse existing primary hits to find overlapping hits
mm_reg1_t *rp = &r[w[j]];
int sj = rp->qs, ej = rp->qe;
@@ -137,6 +154,7 @@ void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff
}
if (ei > x) uncov_len += ei - x;
}
skip_uncov:
for (j = 0; j < k; ++j) { // traverse existing primary hits again
mm_reg1_t *rp = &r[w[j]];
int sj = rp->qs, ej = rp->qe, min, max, ol;
@@ -144,13 +162,16 @@ void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff
min = 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
if ((float)ol / min - (float)uncov_len / max > mask_level) {
int cnt_sub = 0;
if ((float)ol / min - (float)uncov_len / max > mask_level && uncov_len <= mask_len) { // then this is a secondary hit
int cnt_sub = 0, sci = ri->score;
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 (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 (cnt_sub) ++rp->n_sub;
@@ -164,9 +185,9 @@ set_parent_test:
kfree(km, w);
}
void mm_hit_sort_by_dp(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;
int32_t i, n_aux, n = *n_regs, has_cigar = 0, no_cigar = 0;
mm128_t *aux;
mm_reg1_t *t;
@@ -175,14 +196,18 @@ void mm_hit_sort_by_dp(void *km, int *n_regs, mm_reg1_t *r)
t = (mm_reg1_t*)kmalloc(km, n * sizeof(mm_reg1_t));
for (i = n_aux = 0; i < n; ++i) {
if (r[i].inv || r[i].cnt > 0) { // squeeze out elements with cnt==0 (soft deleted)
assert(r[i].p);
aux[n_aux].x = (uint64_t)r[i].p->dp_max << 32 | r[i].hash;
int score;
if (r[i].p) score = r[i].p->dp_max, has_cigar = 1;
else score = r[i].score, no_cigar = 1;
if (r[i].is_alt) score = mm_alt_score(score, alt_diff_frac);
aux[n_aux].x = (uint64_t)score << 32 | r[i].hash;
aux[n_aux++].y = i;
} else if (r[i].p) {
free(r[i].p);
r[i].p = 0;
}
}
assert(has_cigar + no_cigar == 1);
radix_sort_128x(aux, aux + n_aux);
for (i = n_aux - 1; i >= 0; --i)
t[n_aux - 1 - i] = r[aux[i].y];
@@ -287,64 +312,6 @@ int mm_squeeze_a(void *km, int n_regs, mm_reg1_t *regs, mm128_t *a)
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 = &regs[(int32_t)aux[i-1]], *r1 = &regs[(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 = &regs[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)
{
int s, i, j, acc_qlen[MM_MAX_SEG+1], qlen_sum = 0;
@@ -441,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;
float uniq_ratio;
int i;
if (n_regs == 0) return;
for (i = 0; i < n_regs; ++i)
if (regs[i].parent == regs[i].id)
sum_sc += regs[i].score;
+187 -8
View File
@@ -31,6 +31,16 @@ typedef struct mm_idx_bucket_s {
void *h; // hash table indexing _p_ and minimizers appearing once
} 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 *mi;
@@ -48,10 +58,17 @@ void mm_idx_destroy(mm_idx_t *mi)
uint32_t i;
if (mi == 0) return;
if (mi->h) kh_destroy(str, (khash_t(str)*)mi->h);
for (i = 0; i < 1U<<mi->b; ++i) {
free(mi->B[i].p);
free(mi->B[i].a.a);
kh_destroy(idx, (idxhash_t*)mi->B[i].h);
if (mi->B) {
for (i = 0; i < 1U<<mi->b; ++i) {
free(mi->B[i].p);
free(mi->B[i].a.a);
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) {
for (i = 0; i < mi->n_seq; ++i)
@@ -100,8 +117,8 @@ void mm_idx_stat(const mm_idx_t *mi)
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",
__func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), n, 100.0*n1/n, (double)sum / n, (double)len / sum);
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, (long)len);
}
int mm_idx_index_name(mm_idx_t *mi)
@@ -299,6 +316,7 @@ static void *worker_pipeline(void *shared, int step, void *in)
} else seq->name = 0;
seq->len = s->seq[i].l_seq;
seq->offset = p->sum_len;
seq->is_alt = 0;
// copy the sequence
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
@@ -370,7 +388,9 @@ mm_idx_t *mm_idx_str(int w, int k, int is_hpc, int bucket_bits, int n, const cha
uint64_t sum_len = 0;
mm128_v a = {0,0,0};
mm_idx_t *mi;
khash_t(str) *h;
int i, flag = 0;
if (n <= 0) return 0;
for (i = 0; i < n; ++i) // get the total length
sum_len += strlen(seq[i]);
@@ -381,16 +401,21 @@ mm_idx_t *mm_idx_str(int w, int k, int is_hpc, int bucket_bits, int n, const cha
mi->n_seq = n;
mi->seq = (mm_idx_seq_t*)kcalloc(mi->km, n, sizeof(mm_idx_seq_t)); // ->seq is allocated from km
mi->S = (uint32_t*)calloc((sum_len + 7) / 8, 4);
mi->h = h = kh_init(str);
for (i = 0, sum_len = 0; i < n; ++i) {
const char *s = seq[i];
mm_idx_seq_t *p = &mi->seq[i];
uint32_t j;
if (name && name[i]) {
int absent;
p->name = (char*)kmalloc(mi->km, strlen(name[i]) + 1);
strcpy(p->name, name[i]);
kh_put(str, h, p->name, &absent);
assert(absent);
}
p->offset = sum_len;
p->len = strlen(s);
p->is_alt = 0;
for (j = 0; j < p->len; ++j) {
int c = seq_nt4_table[(uint8_t)s[j]];
uint64_t o = sum_len + j;
@@ -477,6 +502,7 @@ mm_idx_t *mm_idx_load(FILE *fp)
}
fread(&s->len, 4, 1, fp);
s->offset = sum_len;
s->is_alt = 0;
sum_len += s->len;
}
for (i = 0; i < 1<<mi->b; ++i) {
@@ -510,14 +536,19 @@ mm_idx_t *mm_idx_load(FILE *fp)
int64_t mm_idx_is_idx(const char *fn)
{
int fd, is_idx = 0;
off_t ret, off_end;
int64_t ret, off_end;
char magic[4];
if (strcmp(fn, "-") == 0) return 0; // read from pipe; not an index
fd = open(fn, O_RDONLY);
if (fd < 0) return -1; // error
#ifdef WIN32
if ((off_end = _lseeki64(fd, 0, SEEK_END)) >= 4) {
_lseeki64(fd, 0, SEEK_SET);
#else
if ((off_end = lseek(fd, 0, SEEK_END)) >= 4) {
lseek(fd, 0, SEEK_SET);
#endif // WIN32
ret = read(fd, magic, 4);
if (ret == 4 && strncmp(magic, MM_IDX_MAGIC, 4) == 0)
is_idx = 1;
@@ -563,7 +594,7 @@ mm_idx_t *mm_idx_reader_read(mm_idx_reader_t *r, int n_threads)
mi = mm_idx_gen(r->fp.seq, r->opt.w, r->opt.k, r->opt.bucket_bits, r->opt.flag, r->opt.mini_batch_size, n_threads, r->opt.batch_size);
if (mi) {
if (r->fp_out) mm_idx_dump(r->fp_out, mi);
++r->n_parts;
mi->index = r->n_parts++;
}
return mi;
}
@@ -572,3 +603,151 @@ int mm_idx_reader_eof(const mm_idx_reader_t *r) // TODO: in extremely rare cases
{
return r->is_idx? (feof(r->fp.idx) || ftell(r->fp.idx) == r->idx_size) : mm_bseq_eof(r->fp.seq);
}
#include <ctype.h>
#include <zlib.h>
#include "ksort.h"
#include "kseq.h"
KSTREAM_DECLARE(gzFile, gzread)
int mm_idx_alt_read(mm_idx_t *mi, const char *fn)
{
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;
}
#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;
kstream_t *ks;
kstring_t str = {0,0,0};
mm_idx_intv_t *I;
fp = fn && strcmp(fn, "-")? gzopen(fn, "r") : gzdopen(fileno(stdin), "r");
if (fp == 0) return 0;
I = (mm_idx_intv_t*)calloc(mi->n_seq, sizeof(*I));
ks = ks_init(fp);
while (ks_getuntil(ks, KS_SEP_LINE, &str, 0) >= 0) {
mm_idx_intv_t *r;
mm_idx_intv1_t t = {-1,-1,-1,-1,0};
char *p, *q, *bl, *bs;
int32_t i, id = -1, n_blk = 0;
for (p = q = str.s, i = 0;; ++p) {
if (*p == 0 || *p == '\t') {
int32_t c = *p;
*p = 0;
if (i == 0) { // chr
id = mm_idx_name2id(mi, q);
if (id < 0) break; // unknown name; TODO: throw a warning
} else if (i == 1) { // start
t.st = atol(q); // TODO: watch out integer overflow!
if (t.st < 0) break;
} else if (i == 2) { // end
t.en = atol(q);
if (t.en < 0) break;
} else if (i == 4) { // BED score
t.score = atol(q);
} else if (i == 5) { // strand
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;
++i, q = p + 1;
}
}
if (id < 0 || t.st < 0 || t.st >= t.en) continue;
r = &I[id];
if (i >= 11 && read_junc) { // BED12
int32_t st, sz, en;
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);
gzclose(fp);
return I;
}
int mm_idx_bed_read(mm_idx_t *mi, const char *fn, int read_junc)
{
int32_t i;
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;
}
int mm_idx_bed_junc(const mm_idx_t *mi, int32_t ctg, int32_t st, int32_t en, uint8_t *s)
{
int32_t i, left, right;
mm_idx_intv_t *r;
memset(s, 0, en - st);
if (mi->I == 0 || ctg < 0 || ctg >= mi->n_seq) return -1;
r = &mi->I[ctg];
left = 0, right = r->n;
while (right > left) {
int32_t mid = left + ((right - left) >> 1);
if (r->a[mid].st >= st) right = mid;
else left = mid + 1;
}
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;
}
+21 -14
View File
@@ -18,15 +18,14 @@
* | | | |
* p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr
*/
#define MIN_CORE_SIZE 0x80000
typedef struct header_t {
size_t size;
struct header_t *ptr;
} header_t;
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 */
} kmem_t;
@@ -36,31 +35,39 @@ static void panic(const char *s)
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)
{
kmem_t *km = (kmem_t*)_km;
void *km_par;
header_t *p, *q;
if (km == NULL) return;
km_par = km->par;
for (p = km->core_head; p != NULL;) {
q = p->ptr;
free(p);
kfree(km_par, p);
p = q;
}
free(km);
kfree(km_par, km);
}
static header_t *morecore(kmem_t *km, size_t nu)
{
header_t *q;
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);
q = (header_t*)malloc(bytes);
q = (header_t*)kmalloc(km->par, bytes);
if (!q) panic("[morecore] insufficient memory");
q->ptr = km->core_head, q->size = nu, km->core_head = q;
p = (size_t*)(q + 1);
@@ -125,7 +132,7 @@ void *kmalloc(void *_km, size_t n_bytes)
if (n_bytes == 0) return 0;
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 */
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
{
kmem_t *km = (kmem_t*)_km;
size_t n_units, *p, *q;
size_t cap, *p, *q;
if (n_bytes == 0) {
kfree(km, ap); return 0;
}
if (km == NULL) return realloc(ap, 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;
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);
memcpy(q, ap, (*p - 1) * sizeof(header_t));
memcpy(q, ap, cap);
kfree(km, ap);
return q;
}
+49
View File
@@ -17,6 +17,7 @@ void *kcalloc(void *km, size_t count, size_t size);
void kfree(void *km, void *ptr);
void *km_init(void);
void *km_init2(void *km_par, size_t min_core_size);
void km_destroy(void *km);
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
#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
+120
View File
@@ -0,0 +1,120 @@
#ifndef KETOPT_H
#define KETOPT_H
#include <string.h> /* for strchr() and strncmp() */
#define ko_no_argument 0
#define ko_required_argument 1
#define ko_optional_argument 2
typedef struct {
int ind; /* equivalent to optind */
int opt; /* equivalent to optopt */
char *arg; /* equivalent to optarg */
int longidx; /* index of a long option; or -1 if short */
/* private variables not intended for external uses */
int i, pos, n_args;
} ketopt_t;
typedef struct {
char *name;
int has_arg;
int val;
} ko_longopt_t;
static ketopt_t KETOPT_INIT = { 1, 0, 0, -1, 1, 0, 0 };
static void ketopt_permute(char *argv[], int j, int n) /* move argv[j] over n elements to the left */
{
int k;
char *p = argv[j];
for (k = 0; k < n; ++k)
argv[j - k] = argv[j - k - 1];
argv[j - k] = p;
}
/**
* Parse command-line options and arguments
*
* This fuction has a similar interface to GNU's getopt_long(). Each call
* parses one option and returns the option name. s->arg points to the option
* argument if present. The function returns -1 when all command-line arguments
* are parsed. In this case, s->ind is the index of the first non-option
* argument.
*
* @param s status; shall be initialized to KETOPT_INIT on the first call
* @param argc length of argv[]
* @param argv list of command-line arguments; argv[0] is ignored
* @param permute non-zero to move options ahead of non-option arguments
* @param ostr option string
* @param longopts long options
*
* @return ASCII for a short option; ko_longopt_t::val for a long option; -1 if
* argv[] is fully processed; '?' for an unknown option or an ambiguous
* long option; ':' if an option argument is missing
*/
static int ketopt(ketopt_t *s, int argc, char *argv[], int permute, const char *ostr, const ko_longopt_t *longopts)
{
int opt = -1, i0, j;
if (permute) {
while (s->i < argc && (argv[s->i][0] != '-' || argv[s->i][1] == '\0'))
++s->i, ++s->n_args;
}
s->arg = 0, s->longidx = -1, i0 = s->i;
if (s->i >= argc || argv[s->i][0] != '-' || argv[s->i][1] == '\0') {
s->ind = s->i - s->n_args;
return -1;
}
if (argv[s->i][0] == '-' && argv[s->i][1] == '-') { /* "--" or a long option */
if (argv[s->i][2] == '\0') { /* a bare "--" */
ketopt_permute(argv, s->i, s->n_args);
++s->i, s->ind = s->i - s->n_args;
return -1;
}
s->opt = 0, opt = '?', s->pos = -1;
if (longopts) { /* parse long options */
int k, n_exact = 0, n_partial = 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 (k = 0; longopts[k].name != 0; ++k)
if (strncmp(&argv[s->i][2], longopts[k].name, j - 2) == 0) {
if (longopts[k].name[j - 2] == 0) ++n_exact, o_exact = &longopts[k];
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;
if (argv[s->i][j] == '=') s->arg = &argv[s->i][j + 1];
if (o->has_arg == 1 && argv[s->i][j] == '\0') {
if (s->i < argc - 1) s->arg = argv[++s->i];
else opt = ':'; /* missing option argument */
}
}
}
} else { /* a short option */
char *p;
if (s->pos == 0) s->pos = 1;
opt = s->opt = argv[s->i][s->pos++];
p = strchr((char*)ostr, opt);
if (p == 0) {
opt = '?'; /* unknown option */
} else if (p[1] == ':') {
if (argv[s->i][s->pos] == 0) {
if (s->i < argc - 1) s->arg = argv[++s->i];
else opt = ':'; /* missing option argument */
} else s->arg = &argv[s->i][s->pos];
s->pos = -1;
}
}
if (s->pos < 0 || argv[s->i][s->pos] == 0) {
++s->i, s->pos = 0;
if (s->n_args > 0) /* permute */
for (j = i0; j < s->i; ++j)
ketopt_permute(argv, j, s->n_args);
}
s->ind = s->i - s->n_args;
return opt;
}
#endif
+474
View File
@@ -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.__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
+10 -2
View File
@@ -37,6 +37,14 @@
#define KS_SEP_LINE 2 // line separator: "\n" (Unix) or "\r\n" (Windows)
#define KS_SEP_MAX 2
#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 __KS_TYPE(type_t) \
typedef struct __kstream_t { \
int begin, end; \
@@ -64,7 +72,7 @@
}
#define __KS_INLINED(__read) \
static inline int ks_getc(kstream_t *ks) \
static inline klib_unused int ks_getc(kstream_t *ks) \
{ \
if (ks->is_eof && ks->begin >= ks->end) return -1; \
if (ks->begin >= ks->end) { \
@@ -81,7 +89,7 @@
#ifndef KSTRING_T
#define KSTRING_T kstring_t
typedef struct __kstring_t {
unsigned l, m;
size_t l, m;
char *s;
} kstring_t;
#endif
+1 -1
View File
@@ -37,7 +37,7 @@ typedef struct {
int depth;
} 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) \
void ks_heapdown_##name(size_t i, size_t n, type_t l[]) \
+1 -1
View File
@@ -61,7 +61,7 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
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,
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);
+19 -20
View File
@@ -17,18 +17,20 @@
void __cpuidex(int cpuid[4], int func_id, int subfunc_id)
{
#if defined(__x86_64__)
asm volatile ("cpuid"
__asm__ volatile ("cpuid"
: "=a" (cpuid[0]), "=b" (cpuid[1]), "=c" (cpuid[2]), "=d" (cpuid[3])
: "0" (func_id), "2" (subfunc_id));
#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])
: "0" (func_id), "2" (subfunc_id));
#endif
}
#endif
int x86_simd(void)
static int ksw_simd = -1;
static int x86_simd(void)
{
int flag = 0, cpuid[4], max_id;
__cpuidex(cpuid, 0, 0);
@@ -54,11 +56,10 @@ 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_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;
simd = x86_simd();
if (simd & SIMD_SSE4_1)
if (ksw_simd < 0) ksw_simd = x86_simd();
if (ksw_simd & SIMD_SSE4_1)
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);
else abort();
}
@@ -70,28 +71,26 @@ void ksw_extd2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
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,
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;
simd = x86_simd();
if (simd & SIMD_SSE4_1)
if (ksw_simd < 0) ksw_simd = x86_simd();
if (ksw_simd & SIMD_SSE4_1)
ksw_extd2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, ez);
else if (simd & SIMD_SSE2)
else if (ksw_simd & SIMD_SSE2)
ksw_extd2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, e2, w, zdrop, end_bonus, flag, ez);
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,
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,
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,
int8_t q, int8_t e, int8_t q2, int8_t noncan, int zdrop, int flag, ksw_extz_t *ez);
unsigned simd;
simd = x86_simd();
if (simd & SIMD_SSE4_1)
ksw_exts2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, flag, ez);
else if (simd & SIMD_SSE2)
ksw_exts2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, flag, 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);
if (ksw_simd < 0) ksw_simd = x86_simd();
if (ksw_simd & SIMD_SSE4_1)
ksw_exts2_sse41(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, junc_bonus, flag, junc, ez);
else if (ksw_simd & SIMD_SSE2)
ksw_exts2_sse2(km, qlen, query, tlen, target, m, mat, q, e, q2, noncan, zdrop, junc_bonus, flag, junc, ez);
else abort();
}
#endif
+8
View File
@@ -4,15 +4,23 @@
#include "ksw2.h"
#ifdef __SSE2__
#ifdef USE_SIMDE
#include <simde/x86/sse2.h>
#else
#include <emmintrin.h>
#endif
#ifdef KSW_SSE2_ONLY
#undef __SSE4_1__
#endif
#ifdef __SSE4_1__
#ifdef USE_SIMDE
#include <simde/x86/sse4.1.h>
#else
#include <smmintrin.h>
#endif
#endif
#ifdef KSW_CPU_DISPATCH
#ifdef __SSE4_1__
+58 -18
View File
@@ -4,27 +4,34 @@
#include "ksw2.h"
#ifdef __SSE2__
#ifdef USE_SIMDE
#include <simde/x86/sse2.h>
#else
#include <emmintrin.h>
#endif
#ifdef KSW_SSE2_ONLY
#undef __SSE4_1__
#endif
#ifdef __SSE4_1__
#ifdef USE_SIMDE
#include <simde/x86/sse4.1.h>
#else
#include <smmintrin.h>
#endif
#endif
#ifdef KSW_CPU_DISPATCH
#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,
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
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
#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,
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
{
#define __dp_code_block1 \
@@ -100,7 +107,7 @@ void ksw_exts2_sse(void *km, int qlen, const uint8_t *query, int tlen, const uin
for (t = 0; t < tlen_ * 16; ++t) H[t] = KSW_NEG_INF;
}
if (with_cigar) {
mem2 = (uint8_t*)kmalloc(km, ((qlen + tlen - 1) * n_col_ + 1) * 16);
mem2 = (uint8_t*)kmalloc(km, ((size_t)(qlen + tlen - 1) * n_col_ + 1) * 16);
p = (__m128i*)(((size_t)mem2 + 15) >> 4 << 4);
off = (int*)kmalloc(km, (qlen + tlen - 1) * sizeof(int) * 2);
off_end = off + qlen + tlen - 1;
@@ -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)) {
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);
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);
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 (!(flag & KSW_EZ_REV_CIGAR)) {
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;
}
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;
}
}
+8
View File
@@ -3,15 +3,23 @@
#include "ksw2.h"
#ifdef __SSE2__
#ifdef USE_SIMDE
#include <simde/x86/sse2.h>
#else
#include <emmintrin.h>
#endif
#ifdef KSW_SSE2_ONLY
#undef __SSE4_1__
#endif
#ifdef __SSE4_1__
#ifdef USE_SIMDE
#include <simde/x86/sse4.1.h>
#else
#include <smmintrin.h>
#endif
#endif
#ifdef KSW_CPU_DISPATCH
#ifdef __SSE4_1__
+6 -1
View File
@@ -1,9 +1,14 @@
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <emmintrin.h>
#include "ksw2.h"
#ifdef USE_SIMDE
#include <simde/x86/sse2.h>
#else
#include <emmintrin.h>
#endif
#ifdef __GNUC__
#define LIKELY(x) __builtin_expect((x),1)
#define UNLIKELY(x) __builtin_expect((x),0)
+353
View File
@@ -0,0 +1,353 @@
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "mmpriv.h"
#include "kalloc.h"
#include "krmq.h"
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;
}
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) {
if (dr > dq) 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
+237 -153
View File
@@ -1,16 +1,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "bseq.h"
#include "minimap.h"
#include "mmpriv.h"
#ifdef HAVE_GETOPT
#include <getopt.h>
#else
#include "getopt.h"
#endif
#include "ketopt.h"
#define MM_VERSION "2.11-r797"
#define MM_VERSION "2.20-r1061"
#ifdef __linux__
#include <sys/resource.h>
@@ -26,62 +23,83 @@ void liftrlimit()
void liftrlimit() {}
#endif
static struct option long_options[] = {
{ "bucket-bits", required_argument, 0, 0 },
{ "mb-size", required_argument, 0, 'K' },
{ "seed", required_argument, 0, 0 },
{ "no-kalloc", no_argument, 0, 0 },
{ "print-qname", no_argument, 0, 0 },
{ "no-self", no_argument, 0, 'D' },
{ "print-seeds", no_argument, 0, 0 },
{ "max-chain-skip", required_argument, 0, 0 },
{ "min-dp-len", required_argument, 0, 0 },
{ "print-aln-seq", no_argument, 0, 0 },
{ "splice", no_argument, 0, 0 },
{ "cost-non-gt-ag", required_argument, 0, 'C' },
{ "no-long-join", no_argument, 0, 0 },
{ "sr", no_argument, 0, 0 },
{ "frag", required_argument, 0, 0 },
{ "secondary", required_argument, 0, 0 },
{ "cs", optional_argument, 0, 0 },
{ "end-bonus", required_argument, 0, 0 },
{ "no-pairing", no_argument, 0, 0 },
{ "splice-flank", required_argument, 0, 0 },
{ "idx-no-seq", no_argument, 0, 0 },
{ "end-seed-pen", required_argument, 0, 0 }, // 21
{ "for-only", no_argument, 0, 0 }, // 22
{ "rev-only", no_argument, 0, 0 }, // 23
{ "heap-sort", required_argument, 0, 0 }, // 24
{ "all-chain", no_argument, 0, 'P' },
{ "dual", required_argument, 0, 0 }, // 26
{ "max-clip-ratio", required_argument, 0, 0 }, // 27
{ "min-occ-floor", required_argument, 0, 0 }, // 28
{ "MD", no_argument, 0, 0 }, // 29
{ "lj-min-ratio", required_argument, 0, 0 }, // 30
{ "score-N", required_argument, 0, 0 }, // 31
{ "eqx", no_argument, 0, 0 }, // 32
{ "help", no_argument, 0, 'h' },
{ "max-intron-len", required_argument, 0, 'G' },
{ "version", no_argument, 0, 'V' },
{ "min-count", required_argument, 0, 'n' },
{ "min-chain-score",required_argument, 0, 'm' },
{ "mask-level", required_argument, 0, 'M' },
{ "min-dp-score", required_argument, 0, 's' },
{ "sam", no_argument, 0, 'a' },
{ 0, 0, 0, 0}
static ko_longopt_t long_options[] = {
{ "bucket-bits", ko_required_argument, 300 },
{ "mb-size", ko_required_argument, 'K' },
{ "seed", ko_required_argument, 302 },
{ "no-kalloc", ko_no_argument, 303 },
{ "print-qname", ko_no_argument, 304 },
{ "no-self", ko_no_argument, 'D' },
{ "print-seeds", ko_no_argument, 306 },
{ "max-chain-skip", ko_required_argument, 307 },
{ "min-dp-len", ko_required_argument, 308 },
{ "print-aln-seq", ko_no_argument, 309 },
{ "splice", ko_no_argument, 310 },
{ "cost-non-gt-ag", ko_required_argument, 'C' },
{ "no-long-join", ko_no_argument, 312 },
{ "sr", ko_no_argument, 313 },
{ "frag", ko_required_argument, 314 },
{ "secondary", ko_required_argument, 315 },
{ "cs", ko_optional_argument, 316 },
{ "end-bonus", ko_required_argument, 317 },
{ "no-pairing", ko_no_argument, 318 },
{ "splice-flank", ko_required_argument, 319 },
{ "idx-no-seq", ko_no_argument, 320 },
{ "end-seed-pen", ko_required_argument, 321 },
{ "for-only", ko_no_argument, 322 },
{ "rev-only", ko_no_argument, 323 },
{ "heap-sort", ko_required_argument, 324 },
{ "all-chain", ko_no_argument, 'P' },
{ "dual", ko_required_argument, 326 },
{ "max-clip-ratio", ko_required_argument, 327 },
{ "min-occ-floor", ko_required_argument, 328 },
{ "MD", ko_no_argument, 329 },
{ "lj-min-ratio", ko_required_argument, 330 },
{ "score-N", ko_required_argument, 331 },
{ "eqx", ko_no_argument, 332 },
{ "paf-no-hit", ko_no_argument, 333 },
{ "split-prefix", ko_required_argument, 334 },
{ "no-end-flt", ko_no_argument, 335 },
{ "hard-mask-level",ko_no_argument, 336 },
{ "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 },
{ "help", ko_no_argument, 'h' },
{ "max-intron-len", ko_required_argument, 'G' },
{ "version", ko_no_argument, 'V' },
{ "min-count", ko_required_argument, 'n' },
{ "min-chain-score",ko_required_argument, 'm' },
{ "mask-level", ko_required_argument, 'M' },
{ "min-dp-score", ko_required_argument, 's' },
{ "sam", ko_no_argument, 'a' },
{ 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;
char *p;
x = strtod(str, &p);
if (*p == 'G' || *p == 'g') x *= 1e9;
else if (*p == 'M' || *p == 'm') x *= 1e6;
else if (*p == 'K' || *p == 'k') x *= 1e3;
if (*p == 'G' || *p == 'g') x *= 1e9, ++p;
else if (*p == 'M' || *p == 'm') x *= 1e6, ++p;
else if (*p == 'K' || *p == 'k') x *= 1e3, ++p;
if (q) *q = p;
return (int64_t)(x + .499);
}
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, int flag, int long_idx, const char *arg, int yes_to_set)
{
if (yes_to_set) {
@@ -97,11 +115,12 @@ static inline void yes_or_no(mm_mapopt_t *opt, int flag, int long_idx, const cha
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:yY";
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;
mm_mapopt_t opt;
mm_idxopt_t ipt;
int i, c, n_threads = 3, long_idx;
char *fnw = 0, *rg = 0, *s;
int i, c, n_threads = 3, n_parts, old_best_n = -1;
char *fnw = 0, *rg = 0, *junc_bed = 0, *s, *alt_list = 0;
FILE *fp_help = stderr;
mm_idx_reader_t *idx_rdr;
mm_idx_t *mi;
@@ -111,30 +130,35 @@ int main(int argc, char *argv[])
mm_realtime0 = realtime();
mm_set_opt(0, &ipt, &opt);
while ((c = getopt_long(argc, argv, opt_str, long_options, &long_idx)) >= 0) // apply option -x/preset first
while ((c = ketopt(&o, argc, argv, 1, opt_str, long_options)) >= 0) { // test command line options and apply option -x/preset first
if (c == 'x') {
if (mm_set_opt(optarg, &ipt, &opt) < 0) {
fprintf(stderr, "[ERROR] unknown preset '%s'\n", optarg);
if (mm_set_opt(o.arg, &ipt, &opt) < 0) {
fprintf(stderr, "[ERROR] unknown preset '%s'\n", o.arg);
return 1;
}
break;
} else if (c == ':') {
fprintf(stderr, "[ERROR] missing option argument\n");
return 1;
} else if (c == '?') {
fprintf(stderr, "[ERROR] unknown option in \"%s\"\n", argv[o.i - 1]);
return 1;
}
optind = 0; // for musl getopt, optind=0 has the same effect as optreset=1; older libc doesn't have optreset
}
o = KETOPT_INIT;
while ((c = getopt_long(argc, argv, opt_str, long_options, &long_idx)) >= 0) {
if (c == 'w') ipt.w = atoi(optarg);
else if (c == 'k') ipt.k = atoi(optarg);
while ((c = ketopt(&o, argc, argv, 1, opt_str, long_options)) >= 0) {
if (c == 'w') ipt.w = atoi(o.arg);
else if (c == 'k') ipt.k = atoi(o.arg);
else if (c == 'H') ipt.flag |= MM_I_HPC;
else if (c == 'd') fnw = optarg; // the above are indexing related options, except -I
else if (c == 'r') opt.bw = (int)mm_parse_num(optarg);
else if (c == 't') n_threads = atoi(optarg);
else if (c == 'v') mm_verbose = atoi(optarg);
else if (c == 'g') opt.max_gap = (int)mm_parse_num(optarg);
else if (c == 'G') mm_mapopt_max_intron_len(&opt, (int)mm_parse_num(optarg));
else if (c == 'F') opt.max_frag_len = (int)mm_parse_num(optarg);
else if (c == 'N') opt.best_n = atoi(optarg);
else if (c == 'p') opt.pri_ratio = atof(optarg);
else if (c == 'M') opt.mask_level = atof(optarg);
else if (c == 'd') fnw = o.arg; // the above are indexing related options, except -I
else if (c == 't') n_threads = 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') mm_mapopt_max_intron_len(&opt, (int)mm_parse_num(o.arg));
else if (c == 'F') opt.max_frag_len = (int)mm_parse_num(o.arg);
else if (c == 'N') old_best_n = opt.best_n, opt.best_n = atoi(o.arg);
else if (c == 'p') opt.pri_ratio = atof(o.arg);
else if (c == 'M') opt.mask_level = atof(o.arg);
else if (c == 'c') opt.flag |= MM_F_OUT_CG | MM_F_CIGAR;
else if (c == 'D') opt.flag |= MM_F_NO_DIAG;
else if (c == 'P') opt.flag |= MM_F_ALL_CHAINS;
@@ -144,62 +168,88 @@ int main(int argc, char *argv[])
else if (c == 'Y') opt.flag |= MM_F_SOFTCLIP;
else if (c == 'L') opt.flag |= MM_F_LONG_CIGAR;
else if (c == 'y') opt.flag |= MM_F_COPY_COMMENT;
else if (c == 'T') opt.sdust_thres = atoi(optarg);
else if (c == 'n') opt.min_cnt = atoi(optarg);
else if (c == 'm') opt.min_chain_score = atoi(optarg);
else if (c == 'A') opt.a = atoi(optarg);
else if (c == 'B') opt.b = atoi(optarg);
else if (c == 's') opt.min_dp_max = atoi(optarg);
else if (c == 'C') opt.noncan = atoi(optarg);
else if (c == 'I') ipt.batch_size = mm_parse_num(optarg);
else if (c == 'K') opt.mini_batch_size = (int)mm_parse_num(optarg);
else if (c == 'R') rg = optarg;
else if (c == 'T') opt.sdust_thres = atoi(o.arg);
else if (c == 'n') opt.min_cnt = atoi(o.arg);
else if (c == 'm') opt.min_chain_score = atoi(o.arg);
else if (c == 'A') opt.a = atoi(o.arg);
else if (c == 'B') opt.b = 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 == 'I') ipt.batch_size = 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 == 'h') fp_help = stdout;
else if (c == '2') opt.flag |= MM_F_2_IO_THREADS;
else if (c == 0 && long_idx == 0) ipt.bucket_bits = atoi(optarg); // --bucket-bits
else if (c == 0 && long_idx == 2) opt.seed = atoi(optarg); // --seed
else if (c == 0 && long_idx == 3) mm_dbg_flag |= MM_DBG_NO_KALLOC; // --no-kalloc
else if (c == 0 && long_idx == 4) mm_dbg_flag |= MM_DBG_PRINT_QNAME; // --print-qname
else if (c == 0 && long_idx == 6) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_SEED, n_threads = 1; // --print-seed
else if (c == 0 && long_idx == 7) opt.max_chain_skip = atoi(optarg); // --max-chain-skip
else if (c == 0 && long_idx == 8) opt.min_ksw_len = atoi(optarg); // --min-dp-len
else if (c == 0 && long_idx == 9) mm_dbg_flag |= MM_DBG_PRINT_QNAME | MM_DBG_PRINT_ALN_SEQ, n_threads = 1; // --print-aln-seq
else if (c == 0 && long_idx ==10) opt.flag |= MM_F_SPLICE; // --splice
else if (c == 0 && long_idx ==12) opt.flag |= MM_F_NO_LJOIN; // --no-long-join
else if (c == 0 && long_idx ==13) opt.flag |= MM_F_SR; // --sr
else if (c == 0 && long_idx ==17) opt.end_bonus = atoi(optarg); // --end-bonus
else if (c == 0 && long_idx ==18) opt.flag |= MM_F_INDEPEND_SEG; // --no-pairing
else if (c == 0 && long_idx ==20) ipt.flag |= MM_I_NO_SEQ; // --idx-no-seq
else if (c == 0 && long_idx ==21) opt.anchor_ext_shift = atoi(optarg); // --end-seed-pen
else if (c == 0 && long_idx ==22) opt.flag |= MM_F_FOR_ONLY; // --for-only
else if (c == 0 && long_idx ==23) opt.flag |= MM_F_REV_ONLY; // --rev-only
else if (c == 0 && long_idx ==27) opt.max_clip_ratio = atof(optarg); // --max-clip-ratio
else if (c == 0 && long_idx ==28) opt.min_mid_occ = atoi(optarg); // --min-occ-floor
else if (c == 0 && long_idx ==29) opt.flag |= MM_F_OUT_MD; // --MD
else if (c == 0 && long_idx ==30) opt.min_join_flank_ratio = atof(optarg); // --lj-min-ratio
else if (c == 0 && long_idx ==31) opt.sc_ambi = atoi(optarg); // --score-N
else if (c == 0 && long_idx ==32) opt.flag |= MM_F_EQX; // --eqx
else if (c == 0 && long_idx == 14) { // --frag
yes_or_no(&opt, MM_F_FRAG_MODE, long_idx, optarg, 1);
} else if (c == 0 && long_idx == 15) { // --secondary
yes_or_no(&opt, MM_F_NO_PRINT_2ND, long_idx, optarg, 0);
} else if (c == 0 && long_idx == 16) { // --cs
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 == 302) opt.seed = atoi(o.arg); // --seed
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 == 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 == 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 == 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 == 312) opt.flag |= MM_F_NO_LJOIN; // --no-long-join
else if (c == 313) opt.flag |= MM_F_SR; // --sr
else if (c == 317) opt.end_bonus = atoi(o.arg); // --end-bonus
else if (c == 318) opt.flag |= MM_F_INDEPEND_SEG; // --no-pairing
else if (c == 320) ipt.flag |= MM_I_NO_SEQ; // --idx-no-seq
else if (c == 321) opt.anchor_ext_shift = atoi(o.arg); // --end-seed-pen
else if (c == 322) opt.flag |= MM_F_FOR_ONLY; // --for-only
else if (c == 323) opt.flag |= MM_F_REV_ONLY; // --rev-only
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 == 329) opt.flag |= MM_F_OUT_MD; // --MD
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 == 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 == 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 == 337) opt.max_sw_mat = mm_parse_num(o.arg); // --cap-sw-mat
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 == 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);
} else if (c == 315) { // --secondary
yes_or_no(&opt, MM_F_NO_PRINT_2ND, o.longidx, o.arg, 0);
} else if (c == 316) { // --cs
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR;
if (optarg == 0 || strcmp(optarg, "short") == 0) {
if (o.arg == 0 || strcmp(o.arg, "short") == 0) {
opt.flag &= ~MM_F_OUT_CS_LONG;
} else if (strcmp(optarg, "long") == 0) {
} else if (strcmp(o.arg, "long") == 0) {
opt.flag |= MM_F_OUT_CS_LONG;
} else if (strcmp(optarg, "none") == 0) {
} else if (strcmp(o.arg, "none") == 0) {
opt.flag &= ~MM_F_OUT_CS;
} else if (mm_verbose >= 2) {
fprintf(stderr, "[WARNING]\033[1;31m --cs only takes 'short' or 'long'. Invalid values are assumed to be 'short'.\033[0m\n");
}
} else if (c == 0 && long_idx == 19) { // --splice-flank
yes_or_no(&opt, MM_F_SPLICE_FLANK, long_idx, optarg, 1);
} else if (c == 0 && long_idx == 24) { // --heap-sort
yes_or_no(&opt, MM_F_HEAP_SORT, long_idx, optarg, 1);
} else if (c == 0 && long_idx == 26) { // --dual
yes_or_no(&opt, MM_F_NO_DUAL, long_idx, optarg, 0);
} else if (c == 319) { // --splice-flank
yes_or_no(&opt, MM_F_SPLICE_FLANK, o.longidx, o.arg, 1);
} else if (c == 324) { // --heap-sort
yes_or_no(&opt, MM_F_HEAP_SORT, o.longidx, o.arg, 1);
} else if (c == 326) { // --dual
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') {
opt.flag |= MM_F_OUT_CS | MM_F_CIGAR | MM_F_OUT_CS_LONG;
if (mm_verbose >= 2)
@@ -207,30 +257,36 @@ int main(int argc, char *argv[])
} else if (c == 'V') {
puts(MM_VERSION);
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') {
double x;
char *p;
x = strtod(optarg, &p);
x = strtod(o.arg, &p);
if (x < 1.0) opt.mid_occ_frac = x, opt.mid_occ = 0;
else opt.mid_occ = (int)(x + .499);
if (*p == ',') opt.max_occ = (int)(strtod(p+1, &p) + .499);
} else if (c == 'u') {
if (*optarg == 'b') opt.flag |= MM_F_SPLICE_FOR|MM_F_SPLICE_REV; // both strands
else if (*optarg == 'f') opt.flag |= MM_F_SPLICE_FOR, opt.flag &= ~MM_F_SPLICE_REV; // match GT-AG
else if (*optarg == 'r') opt.flag |= MM_F_SPLICE_REV, opt.flag &= ~MM_F_SPLICE_FOR; // match CT-AC (reverse complement of GT-AG)
else if (*optarg == 'n') opt.flag &= ~(MM_F_SPLICE_FOR|MM_F_SPLICE_REV); // don't try to match the GT-AG signal
if (*o.arg == 'b') opt.flag |= MM_F_SPLICE_FOR|MM_F_SPLICE_REV; // both strands
else if (*o.arg == 'f') opt.flag |= MM_F_SPLICE_FOR, opt.flag &= ~MM_F_SPLICE_REV; // match GT-AG
else if (*o.arg == 'r') opt.flag |= MM_F_SPLICE_REV, opt.flag &= ~MM_F_SPLICE_FOR; // match CT-AC (reverse complement of GT-AG)
else if (*o.arg == 'n') opt.flag &= ~(MM_F_SPLICE_FOR|MM_F_SPLICE_REV); // don't try to match the GT-AG signal
else {
fprintf(stderr, "[ERROR]\033[1;31m unrecognized cDNA direction\033[0m\n");
return 1;
}
} else if (c == 'z') {
opt.zdrop = opt.zdrop_inv = strtol(optarg, &s, 10);
opt.zdrop = opt.zdrop_inv = strtol(o.arg, &s, 10);
if (*s == ',') opt.zdrop_inv = strtol(s + 1, &s, 10);
} else if (c == 'O') {
opt.q = opt.q2 = strtol(optarg, &s, 10);
opt.q = opt.q2 = strtol(o.arg, &s, 10);
if (*s == ',') opt.q2 = strtol(s + 1, &s, 10);
} else if (c == 'E') {
opt.e = opt.e2 = strtol(optarg, &s, 10);
opt.e = opt.e2 = strtol(o.arg, &s, 10);
if (*s == ',') opt.e2 = strtol(s + 1, &s, 10);
}
}
@@ -242,14 +298,18 @@ int main(int argc, char *argv[])
ipt.flag |= MM_I_NO_SEQ;
if (mm_check_opt(&ipt, &opt) < 0)
return 1;
if (opt.best_n == 0) {
fprintf(stderr, "[WARNING]\033[1;31m changed '-N 0' to '-N %d --secondary=no'.\033[0m\n", old_best_n);
opt.best_n = old_best_n, opt.flag |= MM_F_NO_PRINT_2ND;
}
if (argc == optind || fp_help == stdout) {
if (argc == o.ind || fp_help == stdout) {
fprintf(fp_help, "Usage: minimap2 [options] <target.fa>|<target.idx> [query.fa] [...]\n");
fprintf(fp_help, "Options:\n");
fprintf(fp_help, " Indexing:\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, " -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, " -d FILE dump index to FILE []\n");
fprintf(fp_help, " Mapping:\n");
@@ -257,7 +317,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 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, " -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, " -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
@@ -274,7 +334,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, " Input/Output:\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, " -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");
@@ -288,25 +348,26 @@ int main(int argc, char *argv[])
fprintf(fp_help, " --version show version number\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, " - map-pb/map-ont: PacBio/Nanopore vs reference mapping\n");
fprintf(fp_help, " - ava-pb/ava-ont: PacBio/Nanopore read overlap\n");
fprintf(fp_help, " - asm5/asm10/asm20: asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\n");
fprintf(fp_help, " - splice: long-read spliced alignment\n");
fprintf(fp_help, " - sr: genomic short-read mapping\n");
fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of command-line options.\n");
fprintf(fp_help, " - map-pb/map-ont - PacBio CLR/Nanopore vs reference mapping\n");
fprintf(fp_help, " - map-hifi - PacBio HiFi reads vs reference mapping\n");
fprintf(fp_help, " - ava-pb/ava-ont - PacBio/Nanopore read overlap\n");
fprintf(fp_help, " - asm5/asm10/asm20 - asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\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");
return fp_help == stdout? 0 : 1;
}
if ((opt.flag & MM_F_SR) && argc - optind > 3) {
if ((opt.flag & MM_F_SR) && argc - o.ind > 3) {
fprintf(stderr, "[ERROR] incorrect input: in the sr mode, please specify no more than two query files.\n");
return 1;
}
idx_rdr = mm_idx_reader_open(argv[optind], &ipt, fnw);
idx_rdr = mm_idx_reader_open(argv[o.ind], &ipt, fnw);
if (idx_rdr == 0) {
fprintf(stderr, "[ERROR] failed to open file '%s'\n", argv[optind]);
fprintf(stderr, "[ERROR] failed to open file '%s': %s\n", argv[o.ind], strerror(errno));
return 1;
}
if (!idx_rdr->is_idx && fnw == 0 && argc - optind < 2) {
if (!idx_rdr->is_idx && fnw == 0 && argc - o.ind < 2) {
fprintf(stderr, "[ERROR] missing input: please specify a query file to map or option -d to keep the index\n");
mm_idx_reader_close(idx_rdr);
return 1;
@@ -314,6 +375,7 @@ int main(int argc, char *argv[])
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");
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)) {
fprintf(stderr, "[ERROR] the prebuilt index doesn't contain sequences.\n");
mm_idx_destroy(mi);
@@ -322,30 +384,52 @@ int main(int argc, char *argv[])
}
if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) {
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 {
mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv);
if (mm_verbose >= 2)
fprintf(stderr, "[WARNING]\033[1;31m For a multi-part index, no @SQ lines will be outputted.\033[0m\n");
ret = mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv);
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");
}
if (ret != 0) {
mm_idx_destroy(mi);
mm_idx_reader_close(idx_rdr);
return 1;
}
}
if (mm_verbose >= 3)
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);
if (argc != optind + 1) mm_mapopt_update(&opt, mi);
if (argc != o.ind + 1) mm_mapopt_update(&opt, 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) continue; // no query files
ret = 0;
if (!(opt.flag & MM_F_FRAG_MODE)) {
for (i = optind + 1; i < argc; ++i)
mm_map_file(mi, argv[i], &opt, n_threads);
for (i = o.ind + 1; i < argc; ++i) {
ret = mm_map_file(mi, argv[i], &opt, n_threads);
if (ret < 0) break;
}
} else {
mm_map_file_frag(mi, argc - (optind + 1), (const char**)&argv[optind + 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);
if (ret < 0) {
fprintf(stderr, "ERROR: failed to map the query file\n");
exit(EXIT_FAILURE);
}
}
n_parts = idx_rdr->n_parts;
mm_idx_reader_close(idx_rdr);
if (opt.split_prefix)
mm_split_merge(argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_parts);
if (fflush(stdout) == EOF) {
fprintf(stderr, "[ERROR] failed to write the results\n");
perror("[ERROR] failed to write the results");
exit(EXIT_FAILURE);
}
@@ -354,7 +438,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "[M::%s] CMD:", __func__);
for (i = 0; i < argc; ++i)
fprintf(stderr, " %s", argv[i]);
fprintf(stderr, "\n[M::%s] Real time: %.3f sec; CPU: %.3f sec\n", __func__, realtime() - mm_realtime0, cputime());
fprintf(stderr, "\n[M::%s] Real time: %.3f sec; CPU: %.3f sec; Peak RSS: %.3f GB\n", __func__, realtime() - mm_realtime0, cputime(), peakrss() / 1024.0 / 1024.0 / 1024.0);
}
return 0;
}
+222 -89
View File
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "kthread.h"
#include "kvec.h"
#include "kalloc.h"
@@ -11,6 +12,7 @@
struct mm_tbuf_s {
void *km;
int rep_len, frag_gap;
};
mm_tbuf_t *mm_tbuf_init(void)
@@ -28,6 +30,11 @@ void mm_tbuf_destroy(mm_tbuf_t *b)
free(b);
}
void *mm_tbuf_get_km(mm_tbuf_t *b)
{
return b->km;
}
static int mm_dust_minier(void *km, int n, mm128_t *a, int l_seq, const char *seq, int sdust_thres)
{
int n_dreg, j, k, u = 0;
@@ -73,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)
KSORT_INIT(heap, mm128_t, heap_lt)
typedef struct {
uint32_t n;
uint32_t q_pos, q_span;
uint32_t seg_id:31, is_tandem:1;
const uint64_t *cr;
} mm_match_t;
static mm_match_t *collect_matches(void *km, int *_n_m, int max_occ, const mm_idx_t *mi, const mm128_v *mv, int64_t *n_a, int *rep_len, int *n_mini_pos, uint64_t **mini_pos)
{
int 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)
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)
{
*is_self = 0;
if (qname && (flag & (MM_F_NO_DIAG|MM_F_NO_DUAL))) {
@@ -144,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;
int64_t j, n_for = 0, n_rev = 0;
mm_match_t *m;
mm_seed_t *m;
mm128_t *a, *heap;
m = collect_matches(km, &n_m, max_occ, mi, mv, n_a, rep_len, n_mini_pos, mini_pos);
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));
a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
@@ -161,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);
while (heap_size > 0) {
mm_match_t *q = &m[heap->y>>32];
mm_seed_t *q = &m[heap->y>>32];
mm128_t *p;
uint64_t r = heap->x;
int32_t is_self, rpos = (uint32_t)r >> 1;
@@ -209,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 i, n_m;
mm_match_t *m;
mm_seed_t *m;
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));
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;
uint32_t k;
for (k = 0; k < q->n; ++k) {
@@ -242,11 +207,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)
{
if (!(opt->flag & MM_F_ALL_CHAINS)) { // don't choose primary mapping(s)
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
mm_set_parent(km, opt->mask_level, 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);
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);
}
}
@@ -255,7 +218,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;
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)
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
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_set_sam_pri(*n_regs, regs);
}
@@ -278,6 +241,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;
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 ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed);
@@ -305,9 +269,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;
} 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;
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;
@@ -327,11 +307,18 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
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);
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->rep_len = rep_len;
regs0 = mm_gen_regs(b->km, hash, qlen_sum, n_regs0, u, a);
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)
for (j = 0; j < n_regs0; ++j)
@@ -351,7 +338,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
free(regs0);
for (i = 0; i < n_segs; ++i) {
mm_set_parent(b->km, opt->mask_level, n_regs[i], regs[i], opt->a * 2 + opt->b); // update mm_reg1_t::parent
mm_set_parent(b->km, opt->mask_level, 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);
mm_set_mapq(b->km, n_regs[i], regs[i], opt->min_chain_score, opt->a, rep_len, is_sr);
}
@@ -389,18 +376,23 @@ mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm
**************************/
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;
mm_bseq_file_t **fp;
const mm_idx_t *mi;
kstring_t str;
int n_parts;
uint32_t *rid_shift;
FILE *fp_split, **fp_parts;
} pipeline_t;
typedef struct {
const pipeline_t *p;
int n_seq, n_frag;
mm_bseq1_t *seq;
int *n_reg, *seg_off, *n_seg;
int *n_reg, *seg_off, *n_seg, *rep_len, *frag_gap;
mm_reg1_t **reg;
mm_tbuf_t **buf;
} step_t;
@@ -421,10 +413,17 @@ static void worker_for(void *_data, long i, int tid) // kt_for() callback
qseqs[j] = s->seq[off + j].seq;
}
if (s->p->opt->flag & MM_F_INDEPEND_SEG) {
for (j = 0; j < s->n_seg[i]; ++j)
for (j = 0; j < s->n_seg[i]; ++j) {
mm_map_frag(s->p->mi, 1, &qlens[j], &qseqs[j], &s->n_reg[off+j], &s->reg[off+j], b, s->p->opt, s->seq[off+j].name);
s->rep_len[off + j] = b->rep_len;
s->frag_gap[off + j] = b->frag_gap;
}
} else {
mm_map_frag(s->p->mi, s->n_seg[i], qlens, qseqs, &s->n_reg[off], &s->reg[off], b, s->p->opt, s->seq[off].name);
for (j = 0; j < s->n_seg[i]; ++j) {
s->rep_len[off + j] = b->rep_len;
s->frag_gap[off + j] = b->frag_gap;
}
}
for (j = 0; j < s->n_seg[i]; ++j) // flip the query strand and coordinate to the original read strand
if (s->n_seg[i] == 2 && ((j == 0 && (pe_ori>>1&1)) || (j == 1 && (pe_ori&1)))) {
@@ -440,6 +439,63 @@ static void worker_for(void *_data, long i, int tid) // kt_for() callback
}
}
static void merge_hits(step_t *s)
{
int f, i, k0, k, max_seg = 0, *n_reg_part, *rep_len_part, *frag_gap_part, *qlens;
void *km;
FILE **fp = s->p->fp_parts;
const mm_mapopt_t *opt = s->p->opt;
km = km_init();
for (f = 0; f < s->n_frag; ++f)
max_seg = max_seg > s->n_seg[f]? max_seg : s->n_seg[f];
qlens = CALLOC(int, max_seg + s->p->n_parts * 3);
n_reg_part = qlens + max_seg;
rep_len_part = n_reg_part + s->p->n_parts;
frag_gap_part = rep_len_part + s->p->n_parts;
for (f = 0, k = k0 = 0; f < s->n_frag; ++f) {
k0 = k;
for (i = 0; i < s->n_seg[f]; ++i, ++k) {
int j, l, t, rep_len = 0;
qlens[i] = s->seq[k].l_seq;
for (j = 0, s->n_reg[k] = 0; j < s->p->n_parts; ++j) {
mm_err_fread(&n_reg_part[j], sizeof(int), 1, fp[j]);
mm_err_fread(&rep_len_part[j], sizeof(int), 1, fp[j]);
mm_err_fread(&frag_gap_part[j], sizeof(int), 1, fp[j]);
s->n_reg[k] += n_reg_part[j];
if (rep_len < rep_len_part[j])
rep_len = rep_len_part[j];
}
s->reg[k] = CALLOC(mm_reg1_t, s->n_reg[k]);
for (j = 0, l = 0; j < s->p->n_parts; ++j) {
for (t = 0; t < n_reg_part[j]; ++t, ++l) {
mm_reg1_t *r = &s->reg[k][l];
uint32_t capacity;
mm_err_fread(r, sizeof(mm_reg1_t), 1, fp[j]);
r->rid += s->p->rid_shift[j];
if (opt->flag & MM_F_CIGAR) {
mm_err_fread(&capacity, 4, 1, fp[j]);
r->p = (mm_extra_t*)calloc(capacity, 4);
r->p->capacity = capacity;
mm_err_fread(r->p, r->p->capacity, 4, fp[j]);
}
}
}
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)) {
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_mapq(km, s->n_reg[k], s->reg[k], opt->min_chain_score, opt->a, rep_len, !!(opt->flag & MM_F_SR));
}
if (s->n_seg[f] == 2 && opt->pe_ori >= 0 && (opt->flag&MM_F_CIGAR))
mm_pair(km, frag_gap_part[0], opt->pe_bonus, opt->a * 2 + opt->b, opt->a, qlens, &s->n_reg[k0], &s->reg[k0]);
}
free(qlens);
km_destroy(km);
}
static void *worker_pipeline(void *shared, int step, void *in)
{
int i, j, k;
@@ -459,9 +515,11 @@ static void *worker_pipeline(void *shared, int step, void *in)
s->buf = (mm_tbuf_t**)calloc(p->n_threads, sizeof(mm_tbuf_t*));
for (i = 0; i < p->n_threads; ++i)
s->buf[i] = mm_tbuf_init();
s->n_reg = (int*)calloc(3 * s->n_seq, sizeof(int));
s->seg_off = s->n_reg + s->n_seq; // seg_off and n_seg are allocated together with n_reg
s->n_reg = (int*)calloc(5 * s->n_seq, sizeof(int));
s->seg_off = s->n_reg + s->n_seq; // seg_off, n_seg, rep_len and frag_gap are allocated together with n_reg
s->n_seg = s->seg_off + s->n_seq;
s->rep_len = s->n_seg + s->n_seq;
s->frag_gap = s->rep_len + s->n_seq;
s->reg = (mm_reg1_t**)calloc(s->n_seq, sizeof(mm_reg1_t*));
for (i = 1, j = 0; i <= s->n_seq; ++i)
if (i == s->n_seq || !frag_mode || !mm_qname_same(s->seq[i-1].name, s->seq[i].name)) {
@@ -472,7 +530,8 @@ static void *worker_pipeline(void *shared, int step, void *in)
return s;
} else free(s);
} else if (step == 1) { // step 1: map
kt_for(p->n_threads, worker_for, in, ((step_t*)in)->n_frag);
if (p->n_parts > 0) merge_hits((step_t*)in);
else kt_for(p->n_threads, worker_for, in, ((step_t*)in)->n_frag);
return in;
} else if (step == 2) { // step 2: output
void *km = 0;
@@ -485,19 +544,35 @@ static void *worker_pipeline(void *shared, int step, void *in)
int seg_st = s->seg_off[k], seg_en = s->seg_off[k] + s->n_seg[k];
for (i = seg_st; i < seg_en; ++i) {
mm_bseq1_t *t = &s->seq[i];
for (j = 0; j < s->n_reg[i]; ++j) {
mm_reg1_t *r = &s->reg[i][j];
assert(!r->sam_pri || r->id == r->parent);
if ((p->opt->flag & MM_F_NO_PRINT_2ND) && r->id != r->parent)
continue;
if (p->opt->split_prefix && p->n_parts == 0) { // then write to temporary files
mm_err_fwrite(&s->n_reg[i], sizeof(int), 1, p->fp_split);
mm_err_fwrite(&s->rep_len[i], sizeof(int), 1, p->fp_split);
mm_err_fwrite(&s->frag_gap[i], sizeof(int), 1, p->fp_split);
for (j = 0; j < s->n_reg[i]; ++j) {
mm_reg1_t *r = &s->reg[i][j];
mm_err_fwrite(r, sizeof(mm_reg1_t), 1, p->fp_split);
if (p->opt->flag & MM_F_CIGAR) {
mm_err_fwrite(&r->p->capacity, 4, 1, p->fp_split);
mm_err_fwrite(r->p, r->p->capacity, 4, p->fp_split);
}
}
} else if (s->n_reg[i] > 0) { // the query has at least one hit
for (j = 0; j < s->n_reg[i]; ++j) {
mm_reg1_t *r = &s->reg[i][j];
assert(!r->sam_pri || r->id == r->parent);
if ((p->opt->flag & MM_F_NO_PRINT_2ND) && r->id != r->parent)
continue;
if (p->opt->flag & MM_F_OUT_SAM)
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
mm_write_paf3(&p->str, mi, t, r, km, p->opt->flag, s->rep_len[i]);
mm_err_puts(p->str.s);
}
} 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)
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, -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
mm_write_paf(&p->str, mi, t, r, km, p->opt->flag);
mm_err_puts(p->str.s);
}
if (s->n_reg[i] == 0 && (p->opt->flag & MM_F_OUT_SAM)) { // write an unmapped record
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_paf3(&p->str, mi, t, 0, 0, p->opt->flag, s->rep_len[i]);
mm_err_puts(p->str.s);
}
}
@@ -506,9 +581,10 @@ static void *worker_pipeline(void *shared, int step, void *in)
free(s->reg[i]);
free(s->seq[i].seq); free(s->seq[i].name);
if (s->seq[i].qual) free(s->seq[i].qual);
if (s->seq[i].comment) free(s->seq[i].comment);
}
}
free(s->reg); free(s->n_reg); free(s->seq); // seg_off and n_seg were allocated with reg; no memory leak here
free(s->reg); free(s->n_reg); free(s->seq); // seg_off, n_seg, rep_len and frag_gap were allocated with reg; no memory leak here
km_destroy(km);
if (mm_verbose >= 3)
fprintf(stderr, "[M::%s::%.3f*%.2f] mapped %d sequences\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), s->n_seq);
@@ -517,32 +593,44 @@ static void *worker_pipeline(void *shared, int step, void *in)
return 0;
}
static mm_bseq_file_t **open_bseqs(int n, const char **fn)
{
mm_bseq_file_t **fp;
int i, j;
fp = (mm_bseq_file_t**)calloc(n, sizeof(mm_bseq_file_t*));
for (i = 0; i < n; ++i) {
if ((fp[i] = mm_bseq_open(fn[i])) == 0) {
if (mm_verbose >= 1)
fprintf(stderr, "ERROR: failed to open file '%s': %s\n", fn[i], strerror(errno));
for (j = 0; j < i; ++j)
mm_bseq_close(fp[j]);
free(fp);
return 0;
}
}
return fp;
}
int mm_map_file_frag(const mm_idx_t *idx, int n_segs, const char **fn, const mm_mapopt_t *opt, int n_threads)
{
int i, j, pl_threads;
int i, pl_threads;
pipeline_t pl;
if (n_segs < 1) return -1;
memset(&pl, 0, sizeof(pipeline_t));
pl.n_fp = n_segs;
pl.fp = (mm_bseq_file_t**)calloc(n_segs, sizeof(mm_bseq_file_t*));
for (i = 0; i < n_segs; ++i) {
pl.fp[i] = mm_bseq_open(fn[i]);
if (pl.fp[i] == 0) {
if (mm_verbose >= 1)
fprintf(stderr, "ERROR: failed to open file '%s'\n", fn[i]);
for (j = 0; j < i; ++j)
mm_bseq_close(pl.fp[j]);
free(pl.fp);
return -1;
}
}
pl.fp = open_bseqs(pl.n_fp, fn);
if (pl.fp == 0) return -1;
pl.opt = opt, pl.mi = idx;
pl.n_threads = n_threads > 1? n_threads : 1;
pl.mini_batch_size = opt->mini_batch_size;
if (opt->split_prefix)
pl.fp_split = mm_split_init(opt->split_prefix, idx);
pl_threads = n_threads == 1? 1 : (opt->flag&MM_F_2_IO_THREADS)? 3 : 2;
kt_pipeline(pl_threads, worker_pipeline, &pl, 3);
free(pl.str.s);
for (i = 0; i < n_segs; ++i)
if (pl.fp_split) fclose(pl.fp_split);
for (i = 0; i < pl.n_fp; ++i)
mm_bseq_close(pl.fp[i]);
free(pl.fp);
return 0;
@@ -552,3 +640,48 @@ int mm_map_file(const mm_idx_t *idx, const char *fn, const mm_mapopt_t *opt, int
{
return mm_map_file_frag(idx, 1, &fn, opt, n_threads);
}
int mm_split_merge(int n_segs, const char **fn, const mm_mapopt_t *opt, int n_split_idx)
{
int i;
pipeline_t pl;
mm_idx_t *mi;
if (n_segs < 1 || n_split_idx < 1) return -1;
memset(&pl, 0, sizeof(pipeline_t));
pl.n_fp = n_segs;
pl.fp = open_bseqs(pl.n_fp, fn);
if (pl.fp == 0) return -1;
pl.opt = opt;
pl.mini_batch_size = opt->mini_batch_size;
pl.n_parts = n_split_idx;
pl.fp_parts = CALLOC(FILE*, pl.n_parts);
pl.rid_shift = CALLOC(uint32_t, pl.n_parts);
pl.mi = mi = mm_split_merge_prep(opt->split_prefix, n_split_idx, pl.fp_parts, pl.rid_shift);
if (pl.mi == 0) {
free(pl.fp_parts);
free(pl.rid_shift);
return -1;
}
for (i = n_split_idx - 1; i > 0; --i)
pl.rid_shift[i] = pl.rid_shift[i - 1];
for (pl.rid_shift[0] = 0, i = 1; i < n_split_idx; ++i)
pl.rid_shift[i] += pl.rid_shift[i - 1];
if (opt->flag & MM_F_OUT_SAM)
for (i = 0; i < (int32_t)pl.mi->n_seq; ++i)
printf("@SQ\tSN:%s\tLN:%d\n", pl.mi->seq[i].name, pl.mi->seq[i].len);
kt_pipeline(2, worker_pipeline, &pl, 3);
free(pl.str.s);
mm_idx_destroy(mi);
free(pl.rid_shift);
for (i = 0; i < n_split_idx; ++i)
fclose(pl.fp_parts[i]);
free(pl.fp_parts);
for (i = 0; i < pl.n_fp; ++i)
mm_bseq_close(pl.fp[i]);
free(pl.fp);
mm_split_rm_tmp(opt->split_prefix, n_split_idx);
return 0;
}
+51 -11
View File
@@ -32,6 +32,11 @@
#define MM_F_OUT_MD 0x1000000
#define MM_F_COPY_COMMENT 0x2000000
#define MM_F_EQX 0x4000000 // use =/X instead of M
#define MM_F_PAF_NO_HIT 0x8000000 // output unmapped reads to PAF
#define MM_F_NO_END_FLT 0x10000000
#define MM_F_HARD_MLEVEL 0x20000000
#define MM_F_SAM_HIT_ONLY 0x40000000
#define MM_F_RMQ 0x80000000LL
#define MM_I_HPC 0x1
#define MM_I_NO_SEQ 0x2
@@ -54,14 +59,18 @@ typedef struct {
char *name; // name of the db sequence
uint64_t offset; // offset in mm_idx_t::S
uint32_t len; // length
uint32_t is_alt;
} mm_idx_seq_t;
typedef struct {
int32_t b, w, k, flag;
uint32_t n_seq; // number of reference sequences
int32_t index;
int32_t n_alt;
mm_idx_seq_t *seq; // sequence name, length and offset
uint32_t *S; // 4-bit packed sequence
struct mm_idx_bucket_s *B; // index (hidden)
struct mm_idx_intv_s *I; // intervals (hidden)
void *km, *h;
} mm_idx_t;
@@ -85,7 +94,7 @@ typedef struct {
int32_t mlen, blen; // seeded exact match length; seeded alignment block length
int32_t n_sub; // number of suboptimal mappings
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;
float div;
mm_extra_t *p;
@@ -94,33 +103,39 @@ typedef struct {
// indexing and mapping options
typedef struct {
short k, w, flag, bucket_bits;
int mini_batch_size;
int64_t mini_batch_size;
uint64_t batch_size;
} mm_idxopt_t;
typedef struct {
int64_t flag; // see MM_F_* macros
int seed;
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_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_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;
int mask_len;
float pri_ratio;
int best_n; // top best_n chains are subjected to DP alignment
int max_join_long, max_join_short;
int min_join_flank_sc;
float min_join_flank_ratio;
float alt_drop;
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 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 end_bonus;
int min_dp_max; // drop an alignment if the score of the max scoring segment is below this threshold
@@ -131,10 +146,13 @@ typedef struct {
int pe_ori, pe_bonus;
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 max_occ;
int mini_batch_size; // size of a batch of query bases to process in parallel
int32_t max_occ, max_max_occ, occ_dist;
int64_t mini_batch_size; // size of a batch of query bases to process in parallel
int64_t max_sw_mat;
const char *split_prefix;
} mm_mapopt_t;
// index reader
@@ -297,6 +315,8 @@ mm_tbuf_t *mm_tbuf_init(void);
*/
void mm_tbuf_destroy(mm_tbuf_t *b);
void *mm_tbuf_get_km(mm_tbuf_t *b);
/**
* Align a query sequence against an index
*
@@ -333,11 +353,31 @@ int mm_map_file(const mm_idx_t *idx, const char *fn, const mm_mapopt_t *opt, int
int mm_map_file_frag(const mm_idx_t *idx, int n_segs, const char **fn, const mm_mapopt_t *opt, int n_threads);
/**
* Generate the cs tag (new in 2.12)
*
* @param km memory blocks; set to NULL if unsure
* @param buf buffer to write the cs/MD tag; typicall NULL on the first call
* @param max_len max length of the buffer; typically set to 0 on the first call
* @param mi index
* @param r alignment
* @param seq query sequence
* @param no_iden true to use : instead of =
*
* @return the length of cs
*/
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_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq);
// query sequence name and sequence in the minimap2 index
int mm_idx_index_name(mm_idx_t *mi);
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_alt_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_junc(const mm_idx_t *mi, int32_t ctg, int32_t st, int32_t en, uint8_t *s);
// deprecated APIs for backward compatibility
void mm_mapopt_init(mm_mapopt_t *opt);
mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads);
+143 -52
View File
@@ -1,4 +1,4 @@
.TH minimap2 1 "20 June 2018" "minimap2-2.11 (r797)" "Bioinformatics tools"
.TH minimap2 1 "27 May 2021" "minimap2-2.20 (r1061)" "Bioinformatics tools"
.SH NAME
.PP
minimap2 - mapping and alignment between collections of DNA sequences
@@ -121,6 +121,14 @@ provided as the target sequences, options
.BR -w ,
.B -I
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
.TP 10
.BI -f \ FLOAT | INT1 [, INT2 ]
@@ -137,22 +145,32 @@ or
.B -xsr
mode, which sets the threshold for a second round of seeding.
.TP
.BI --min-occ-floor \ INT
Force minimap2 to always use k-mers occurring
.BI -U \ INT1 [, INT2 ]
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
times or less [0]. In effect, the max occurrence threshold is set to
the
.RI max{ INT ,
.BR -f }.
basepairs [500].
.TP
.BI -g \ INT
.BI -g \ NUM
Stop chain enlongation if there are no minimizers within
.IR INT -bp
[10000].
.IR NUM -bp
[10k].
.TP
.BI -r \ INT
Bandwidth used in chaining and DP-based alignment [500]. This option
approximately controls the maximum gap size.
.BI -r \ NUM1 [, NUM2 ]
Bandwidth for chaining and base alignment [500,20k].
.I NUM1
is used for initial chaining and alignment extension;
.I NUM2
for RMQ-based re-chaining and closing gaps in alignments.
.TP
.BI -n \ INT
Discard chains consisting of
@@ -193,7 +211,7 @@ Primarily used for all-vs-all read overlapping.
.BI -p \ FLOAT
Minimal secondary-to-primary score ratio to output secondary mappings [0.8].
Between two chains overlaping over half of the shorter chain (controlled by
.BR --mask-level ),
.BR -M ),
the chain with a lower score is secondary to the chain with a higher score.
If the ratio of the scores is below
.IR FLOAT ,
@@ -226,23 +244,44 @@ Mark as secondary a chain that overlaps with a better chain by
.I FLOAT
or more of the shorter chain [0.5]
.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
Honor option
.B -M
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
.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
option makes minimap2 exits the inner loop if it repeatedly sees seeds already
on chains. Set
.I INT
to a large number to switch off this heurstics.
.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
Disable the long gap patching heuristic. When this option is applied, the
maximum alignment gap is mostly controlled by
.BR -r .
.TP
.B --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
Enable the splice alignment mode.
.TP
@@ -252,6 +291,9 @@ applies a second round of chaining with a higher minimizer occurrence threshold
if no good chain is found. In addition, minimap2 attempts to patch gaps between
seeds with ungapped alignment.
.TP
.BI --split-prefix \ STR
Prefix to create temporary files. Typically used for a multi-part index.
.TP
.BR --frag = no | yes
Whether to enable the fragment mode [no]
.TP
@@ -266,6 +308,10 @@ Only map to the reverse complement strand of the reference sequences.
.BR --heap-sort = no | yes
If yes, sort anchors with heap merge, instead of radix sort. Heap merge is
faster for short reads, but slower for long reads. [no]
.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
.TP 10
.BI -A \ INT
@@ -346,6 +392,17 @@ on SIRV data, please add
.B --splice-flank=no
to the command line.
.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
Drop a terminal anchor if
.IR s <log( g )+ INT ,
@@ -357,12 +414,26 @@ the length of the terminal gap in the chain. This option is only effective
with
.BR --splice .
It helps to avoid tiny terminal exons. [6]
.TP
.B --no-end-flt
Don't filter seeds towards the ends of chains before performing base-level
alignment.
.TP
.BI --cap-sw-mem \ NUM
Skip alignment if the DP matrix size is above
.IR NUM .
Set 0 to disable [100m].
.SS Input/output options
.TP 10
.B -a
Generate CIGAR and output alignments in the SAM format. Minimap2 outputs in PAF
by default.
.TP
.BI -o \ FILE
Output alignments to
.I FILE
[stdout].
.TP
.B -Q
Ignore base quality in the input file.
.TP
@@ -437,6 +508,18 @@ memory.
.BR --secondary = yes | no
Whether to output secondary alignments [yes]
.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
Print version number to stdout
.SS Preset options
@@ -450,60 +533,47 @@ Available
.I STR
are:
.RS
.TP 8
.B map-pb
PacBio/Oxford Nanopore read to reference mapping
.RB ( -Hk19 )
.TP
.TP 10
.B map-ont
Slightly more sensitive for Oxford Nanopore to reference mapping
.RB ( -k15 ).
For PacBio reads, HPC minimizers consistently leads to faster performance and
more sensitive results in comparison to normal minimizers. For Oxford Nanopore
data, normal minimizers are better, though not much. The effectiveness of HPC
is determined by the sequencing error mode.
Align noisy long reads of ~10% error rate to a reference genome. This is the
default mode.
.TP
.B map-hifi
Align PacBio high-fidelity (HiFi) reads to a reference genome
.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
.B asm5
Long assembly to reference mapping
.RB ( -k19
.B -w19 -A1 -B19 -O39,81 -E3,1 -s200 -z200
.BR --min-occ-floor=100 ).
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B19 -O39,81 -E3,1 -s200 -z200
.BR -N50 ).
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%.
.TP
.B asm10
Long assembly to reference mapping
.RB ( -k19
.B -w19 -A1 -B9 -O16,41 -E2,1 -s200 -z200
.BR --min-occ-floor=100 ).
.B -w19 -U50,500 --rmq -r100k -g10k -A1 -B9 -O16,41 -E2,1 -s200 -z200
.BR -N50 ).
Up to 10% sequence divergence.
.TP
.B asm20
Long assembly to reference mapping
.RB ( -k19
.B -w10 -A1 -B6 -O6,26 -E2,1 -s200 -z200
.BR --min-occ-floor=100 ).
.B -w10 -U50,500 --rmq -r100k -g10k -A1 -B4 -O6,26 -E2,1 -s200 -z200
.BR -N50 ).
Up to 20% sequence divergence.
.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
Long-read spliced alignment
.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 -C9 -z200 -ub --junc-bonus=9 --cap-sw-mem=0
.BR --splice-flank=yes ).
In the splice mode, 1) long deletions are taken as introns and represented as
the
@@ -513,12 +583,30 @@ costs are different during chaining; 4) the computation of the
.RB ` ms '
tag ignores introns to demote hits to pseudogenes.
.TP
.B splice:hq
Long-read splice alignment for PacBio CCS reads
.RB ( -xsplice
.B -C5 -O6,24
.BR -B4 ).
.TP
.B sr
Short single-end reads without splicing
.RB ( -k21
.B -w11 --sr --frag=yes -A2 -B8 -O12,32 -E2,1 -r50 -p.5 -N20 -f1000,5000 -n2 -m20
.B -s40 -g200 -2K50m --heap-sort=yes
.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
.SS Miscellaneous options
.TP 10
@@ -577,12 +665,15 @@ s2 i Chaining score of the best secondary chain
NM i Total number of mismatches and gaps in the alignment
MD Z To generate the ref sequence in the alignment
AS i DP alignment score
SA Z List of other supplementary alignments
ms i DP score of the max scoring segment in the alignment
nn i Number of ambiguous bases in the alignment
ts A Transcript strand (splice mode only)
cg Z CIGAR string (only in PAF)
cs Z Difference string
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
.PP
+23 -3
View File
@@ -116,8 +116,7 @@ long peakrss(void)
double realtime(void)
{
struct timeval tp;
struct timezone tzp;
gettimeofday(&tp, &tzp);
gettimeofday(&tp, NULL);
return tp.tv_sec + tp.tv_usec * 1e-6;
}
@@ -126,7 +125,27 @@ void mm_err_puts(const char *str)
int ret;
ret = puts(str);
if (ret == EOF) {
fprintf(stderr, "[ERROR] failed to write the results\n");
perror("[ERROR] failed to write the results");
exit(EXIT_FAILURE);
}
}
void mm_err_fwrite(const void *p, size_t size, size_t nitems, FILE *fp)
{
int ret;
ret = fwrite(p, size, nitems, fp);
if (ret == EOF) {
perror("[ERROR] failed to write data");
exit(EXIT_FAILURE);
}
}
void mm_err_fread(void *p, size_t size, size_t nitems, FILE *fp)
{
int ret;
ret = fread(p, size, nitems, fp);
if (ret == EOF) {
perror("[ERROR] failed to read data");
exit(EXIT_FAILURE);
}
}
@@ -140,3 +159,4 @@ KRADIX_SORT_INIT(128x, mm128_t, sort_key_128x, 8)
KRADIX_SORT_INIT(64, uint64_t, sort_key_64, 8)
KSORT_INIT_GENERIC(uint32_t)
KSORT_INIT_GENERIC(uint64_t)
+1007 -50
View File
File diff suppressed because it is too large Load Diff
+33 -12
View File
@@ -4,6 +4,7 @@
#include <assert.h>
#include "minimap.h"
#include "bseq.h"
#include "kseq.h"
#define MM_PARENT_UNSET (-1)
#define MM_PARENT_TMP_PRI (-2)
@@ -28,17 +29,20 @@
#define mm_seq4_set(s, i, c) ((s)[(i)>>3] |= (uint32_t)(c) << (((i)&7)<<2))
#define mm_seq4_get(s, i) ((s)[(i)>>3] >> (((i)&7)<<2) & 0xf)
#define MALLOC(type, len) ((type*)malloc((len) * sizeof(type)))
#define CALLOC(type, len) ((type*)calloc((len), sizeof(type)))
#ifdef __cplusplus
extern "C" {
#endif
#ifndef KSTRING_T
#define KSTRING_T kstring_t
typedef struct __kstring_t {
unsigned l, m;
char *s;
} kstring_t;
#endif
typedef struct {
uint32_t n;
uint32_t q_pos;
uint32_t q_span:31, flt:1;
uint32_t seg_id:31, is_tandem:1;
const uint64_t *cr;
} mm_seed_t;
typedef struct {
int n_u, n_a;
@@ -56,28 +60,38 @@ 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_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);
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, 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, int 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_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_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, int opt_flag, int rep_len);
void mm_idxopt_init(mm_idxopt_t *opt);
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);
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);
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,
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);
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a);
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);
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_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);
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_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_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_by_dp(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);
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_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);
@@ -86,7 +100,14 @@ mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int
void mm_seg_free(void *km, int n_segs, mm_seg_t *segs);
void mm_pair(void *km, int max_gap_ref, int dp_bonus, int sub_diff, int match_sc, const int *qlens, int *n_regs, mm_reg1_t **regs);
FILE *mm_split_init(const char *prefix, const mm_idx_t *mi);
mm_idx_t *mm_split_merge_prep(const char *prefix, int n_splits, FILE **fp, uint32_t *n_seq_part);
int mm_split_merge(int n_segs, const char **fn, const mm_mapopt_t *opt, int n_split_idx);
void mm_split_rm_tmp(const char *prefix, int n_splits);
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_fread(void *p, size_t size, size_t nitems, FILE *fp);
#ifdef __cplusplus
}
+82 -33
View File
@@ -1,4 +1,5 @@
#include <stdio.h>
#include <limits.h>
#include "mmpriv.h"
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));
opt->seed = 11;
opt->mid_occ_frac = 2e-4f;
opt->min_mid_occ = 10;
opt->max_mid_occ = 1000000;
opt->sdust_thres = 0; // no SDUST masking
opt->min_cnt = 3;
opt->min_chain_score = 40;
opt->bw = 500;
opt->bw = 500, opt->bw_long = 20000;
opt->max_gap = 5000;
opt->max_gap_ref = -1;
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_len = INT_MAX;
opt->pri_ratio = 0.8f;
opt->best_n = 5;
opt->max_join_long = 20000;
opt->max_join_short = 2000;
opt->min_join_flank_sc = 1000;
opt->min_join_flank_ratio = 0.5f;
opt->alt_drop = 0.15f;
opt->a = 2, opt->b = 4, opt->q = 4, opt->e = 2, opt->q2 = 24, opt->e2 = 1;
opt->sc_ambi = 1;
@@ -42,6 +51,7 @@ void mm_mapopt_init(mm_mapopt_t *opt)
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
opt->max_clip_ratio = 1.0f;
opt->mini_batch_size = 500000000;
opt->max_sw_mat = 100000000;
opt->pe_ori = 0; // FF
opt->pe_bonus = 33;
@@ -49,12 +59,15 @@ void mm_mapopt_init(mm_mapopt_t *opt)
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;
if (opt->mid_occ <= 0)
if (opt->mid_occ <= 0) {
opt->mid_occ = mm_idx_cal_max_occ(mi, opt->mid_occ_frac);
if (opt->mid_occ < opt->min_mid_occ)
opt->mid_occ = opt->min_mid_occ;
if (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)
fprintf(stderr, "[M::%s::%.3f*%.2f] mid_occ = %d\n", __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), opt->mid_occ);
}
@@ -62,7 +75,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)
{
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)
@@ -70,37 +83,44 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
if (preset == 0) {
mm_idxopt_init(io);
mm_mapopt_init(mo);
} else if (strcmp(preset, "map-ont") == 0) { // this is the same as the default
} else if (strcmp(preset, "ava-ont") == 0) {
io->flag = 0, io->k = 15, io->w = 5;
mo->flag |= MM_F_ALL_CHAINS | MM_F_NO_DIAG | MM_F_NO_DUAL | MM_F_NO_LJOIN;
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
mo->bw = 2000;
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_chain_skip = 25;
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) {
io->flag |= MM_I_HPC, io->k = 19, io->w = 5;
mo->flag |= MM_F_ALL_CHAINS | MM_F_NO_DIAG | MM_F_NO_DUAL | MM_F_NO_LJOIN;
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
} else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
io->flag |= MM_I_HPC, io->k = 19;
} else if (strcmp(preset, "map-ont") == 0) {
io->flag = 0, io->k = 15;
} else if (strcmp(preset, "asm5") == 0) {
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_chain_skip = 25;
mo->bw_long = mo->bw;
mo->occ_dist = 0;
} else if (strcmp(preset, "map-hifi") == 0 || strcmp(preset, "map-ccs") == 0) {
io->flag = 0, io->k = 19, io->w = 19;
mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
mo->min_mid_occ = 100;
mo->max_gap = 10000;
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->best_n = 50;
} else if (strcmp(preset, "asm10") == 0) {
} else if (strncmp(preset, "asm", 3) == 0) {
io->flag = 0, io->k = 19, io->w = 19;
mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = mo->zdrop_inv = 200;
mo->min_mid_occ = 100;
mo->min_dp_max = 200;
mo->best_n = 50;
} 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->bw = mo->bw_long = 100000;
mo->max_gap = 10000;
mo->flag |= MM_F_RMQ;
mo->min_mid_occ = 50, mo->max_mid_occ = 500;
mo->min_dp_max = 200;
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) {
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;
@@ -110,7 +130,7 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
mo->end_bonus = 10;
mo->max_frag_len = 800;
mo->max_gap = 100;
mo->bw = 100;
mo->bw = mo->bw_long = 100;
mo->pri_ratio = 0.5f;
mo->min_cnt = 2;
mo->min_chain_score = 25;
@@ -119,19 +139,38 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
mo->mid_occ = 1000;
mo->max_occ = 5000;
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;
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->noncan = 9;
mo->junc_bonus = 9;
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;
return 0;
}
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 (mm_verbose >= 1)
fprintf(stderr, "[ERROR]\033[1;31m --cs or --MD doesn't work with --split-prefix\033[0m\n");
return -6;
}
if (io->k <= 0 || io->w <= 0) {
if (mm_verbose >= 1)
fprintf(stderr, "[ERROR]\033[1;31m -k and -w must be positive\033[0m\n");
@@ -154,6 +193,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");
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 (mm_verbose >= 1)
fprintf(stderr, "[ERROR]\033[1;31m dual gap penalties violating E1>E2 and O1+E1<O2+E2\033[0m\n");
@@ -169,5 +213,10 @@ int mm_check_opt(const mm_idxopt_t *io, const mm_mapopt_t *mo)
fprintf(stderr, "[ERROR]\033[1;31m Z-drop should not be less than inversion-Z-drop\033[0m\n");
return -5;
}
if ((mo->flag & MM_F_NO_PRINT_2ND) && (mo->flag & MM_F_ALL_CHAINS)) {
if (mm_verbose >= 1)
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 0;
}
+1 -1
View File
@@ -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) {
mm_reg1_t *p = &regs[0][pri[0]];
mm_reg1_t *q = &regs[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->pe_thru = q->pe_thru = 1;
+33 -7
View File
@@ -43,20 +43,24 @@ The following Python script demonstrates the key functionality of mappy:
APIs
----
Mappy implements two classes and one global function.
Mappy implements two classes and two global function.
Class mappy.Aligner
~~~~~~~~~~~~~~~~~~~
.. code:: python
mappy.Aligner(fn_idx_in, preset=None, ...)
mappy.Aligner(fn_idx_in=None, preset=None, ...)
This constructor accepts the following arguments:
* **fn_idx_in**: index or sequence file name. Minimap2 automatically tests the
file type. If a sequence file is provided, minimap2 builds an index. The
sequence file can be optionally gzip'd.
sequence file can be optionally gzip'd. This option has no effect if **seq**
is set.
* **seq**: a single sequence to index. The sequence name will be set to
:code:`N/A`.
* **preset**: minimap2 preset. Currently, minimap2 supports the following
presets: **sr** for single-end short reads; **map-pb** for PacBio
@@ -79,17 +83,28 @@ This constructor accepts the following arguments:
* **n_threads**: number of indexing threads; 3 by default
* **fn_idx_out**: name of file to which the index is written
* **extra_flags**: additional flags defined in minimap.h
* **fn_idx_out**: name of file to which the index is written. This parameter
has no effect if **seq** is set.
* **scoring**: scoring system. It is a tuple/list consisting of 4, 6 or 7
positive integers. The first 4 elements specify match scoring, mismatch
penalty, gap open and gap extension penalty. The 5th and 6th elements, if
present, set long-gap open and long-gap extension penalty. The 7th sets a
mismatch penalty involving ambiguous bases.
.. code:: python
mappy.Aligner.map(seq, seq2=None)
mappy.Aligner.map(seq, seq2=None, cs=False, MD=False)
This method aligns :code:`seq` against the index. It is a generator, *yielding*
a series of :code:`mappy.Alignment` objects. If :code:`seq2` is present, mappy
performs paired-end alignment, assuming the two ends are in the FR orientation.
Alignments of the two ends can be distinguished by the :code:`read_num` field
(see Class mappy.Alignment below).
(see Class mappy.Alignment below). Argument :code:`cs` asks mappy to generate
the :code:`cs` tag; :code:`MD` is similar. These two arguments might slightly
degrade performance and are not enabled by default.
.. code:: python
@@ -99,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
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
~~~~~~~~~~~~~~~~~~~~~
@@ -123,7 +144,7 @@ properties:
* **mlen**: length of the matching bases in the alignment, excluding ambiguous
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
reverse strand; 0 if unknown
@@ -139,6 +160,11 @@ properties:
* **cigar**: CIGAR returned as an array of shape :code:`(n_cigar,2)`. The two
numbers give the length and the operator of each CIGAR operation.
* **MD**: the :code:`MD` tag as in the SAM format. It is an empty string unless
the :code:`MD` argument is applied when calling :code:`mappy.Aligner.map()`.
* **cs**: the :code:`cs` tag.
An :code:`Alignment` object can be converted to a string with :code:`str()` in
the following format:
+23 -4
View File
@@ -73,13 +73,17 @@ static inline void mm_reset_timer(void)
extern unsigned char seq_comp_table[256];
static inline mm_reg1_t *mm_map_aux(const mm_idx_t *mi, const char *seq1, const char *seq2, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt)
{
mm_reg1_t *r;
Py_BEGIN_ALLOW_THREADS
if (seq2 == 0) {
return mm_map(mi, strlen(seq1), seq1, n_regs, b, opt, NULL);
r = mm_map(mi, strlen(seq1), seq1, n_regs, b, opt, NULL);
} else {
int _n_regs[2];
mm_reg1_t *regs[2];
char *seq[2];
int i, len[2];
len[0] = strlen(seq1);
len[1] = strlen(seq2);
seq[0] = (char*)seq1;
@@ -97,8 +101,11 @@ static inline mm_reg1_t *mm_map_aux(const mm_idx_t *mi, const char *seq1, const
regs[0] = (mm_reg1_t*)realloc(regs[0], sizeof(mm_reg1_t) * (*n_regs));
memcpy(&regs[0][_n_regs[0]], regs[1], _n_regs[1] * sizeof(mm_reg1_t));
free(regs[1]);
return regs[0];
r = regs[0];
}
Py_END_ALLOW_THREADS
return r;
}
static inline char *mappy_revcomp(int len, const uint8_t *seq)
@@ -119,8 +126,8 @@ static char *mappy_fetch_seq(const mm_idx_t *mi, const char *name, int st, int e
*len = 0;
rid = mm_idx_name2id(mi, name);
if (rid < 0) return 0;
if (st >= mi->seq[rid].len || st >= en) return 0;
if (en < 0 || en > mi->seq[rid].len)
if ((uint32_t)st >= mi->seq[rid].len || st >= en) return 0;
if (en < 0 || (uint32_t)en > mi->seq[rid].len)
en = mi->seq[rid].len;
s = (char*)malloc(en - st + 1);
*len = mm_idx_getseq(mi, rid, st, en, (uint8_t*)s);
@@ -130,4 +137,16 @@ static char *mappy_fetch_seq(const mm_idx_t *mi, const char *name, int st, int e
return s;
}
static mm_idx_t *mappy_idx_seq(int w, int k, int is_hpc, int bucket_bits, const char *seq, int len)
{
const char *fake_name = "N/A";
char *s;
mm_idx_t *mi;
s = (char*)calloc(len + 1, 1);
memcpy(s, seq, len);
mi = mm_idx_str(w, k, is_hpc, bucket_bits, 1, (const char**)&s, (const char**)&fake_name);
free(s);
return mi;
}
#endif
+27 -8
View File
@@ -6,40 +6,55 @@ cdef extern from "minimap.h":
#
ctypedef struct mm_idxopt_t:
short k, w, flag, bucket_bits
int mini_batch_size
int64_t mini_batch_size
uint64_t batch_size
ctypedef struct mm_mapopt_t:
int64_t flag
int seed
int sdust_thres
int flag
int bw
int max_qlen
int bw, bw_long
int max_gap, max_gap_ref
int max_frag_len
int max_chain_skip
int max_chain_skip, max_chain_iter
int min_cnt
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
int mask_len
float pri_ratio
int best_n
int max_join_long, max_join_short
int min_join_flank_sc
float min_join_flank_ratio;
float alt_drop
int a, b, q, e, q2, e2
int sc_ambi
int noncan
int junc_bonus
int zdrop, zdrop_inv
int end_bonus
int min_dp_max
int min_ksw_len
int anchor_ext_len, anchor_ext_shift
float max_clip_ratio
int pe_ori, pe_bonus
float mid_occ_frac
int32_t min_mid_occ
int32_t mid_occ
int32_t max_occ
int mini_batch_size
int64_t mini_batch_size
int64_t max_sw_mat
const char *split_prefix
int mm_set_opt(char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
int mm_verbose
@@ -86,6 +101,9 @@ cdef extern from "minimap.h":
mm_tbuf_t *mm_tbuf_init()
void mm_tbuf_destroy(mm_tbuf_t *b)
void *mm_tbuf_get_km(mm_tbuf_t *b)
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_MD(void *km, char **buf, int *max_len, const mm_idx_t *mi, const mm_reg1_t *r, const char *seq)
#
# Helper header (because it is hard to expose mm_reg1_t with Cython)
@@ -106,6 +124,7 @@ cdef extern from "cmappy.h":
void mm_free_reg1(mm_reg1_t *r)
mm_reg1_t *mm_map_aux(const mm_idx_t *mi, const char *seq1, const char *seq2, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt)
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)
ctypedef struct kstring_t:
unsigned l, m
+85 -24
View File
@@ -3,7 +3,7 @@ from libc.stdlib cimport free
cimport cmappy
import sys
__version__ = '2.11'
__version__ = '2.20'
cmappy.mm_reset_timer()
@@ -14,9 +14,9 @@ cdef class Alignment:
cdef int8_t _strand, _trans_strand
cdef uint8_t _mapq, _is_primary
cdef int _seg_id
cdef _ctg, _cigar # these are python objects
cdef _ctg, _cigar, _cs, _MD # these are python objects
def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand, seg_id):
def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand, seg_id, cs_str, MD_str):
self._ctg = ctg if isinstance(ctg, str) else ctg.decode()
self._ctg_len, self._r_st, self._r_en = cl, cs, ce
self._strand, self._q_st, self._q_en = strand, qs, qe
@@ -26,6 +26,8 @@ cdef class Alignment:
self._is_primary = is_primary
self._trans_strand = trans_strand
self._seg_id = seg_id
self._cs = cs_str
self._MD = MD_str
@property
def ctg(self): return self._ctg
@@ -72,6 +74,12 @@ cdef class Alignment:
@property
def read_num(self): return self._seg_id + 1
@property
def cs(self): return self._cs
@property
def MD(self): return self._MD
@property
def cigar_str(self):
return "".join(map(lambda x: str(x[0]) + 'MIDNSH'[x[1]], self._cigar))
@@ -85,8 +93,10 @@ cdef class Alignment:
if self._trans_strand > 0: ts = 'ts:A:+'
elif self._trans_strand < 0: ts = 'ts:A:-'
else: ts = 'ts:A:.'
return "\t".join([str(self._q_st), str(self._q_en), strand, self._ctg, str(self._ctg_len), str(self._r_st), str(self._r_en),
str(self._mlen), str(self._blen), str(self._mapq), tp, ts, "cg:Z:" + self.cigar_str])
a = [str(self._q_st), str(self._q_en), strand, self._ctg, str(self._ctg_len), str(self._r_st), str(self._r_en),
str(self._mlen), str(self._blen), str(self._mapq), tp, ts, "cg:Z:" + self.cigar_str]
if self._cs != "": a.append("cs:Z:" + self._cs)
return "\t".join(a)
cdef class ThreadBuffer:
cdef cmappy.mm_tbuf_t *_b
@@ -102,7 +112,8 @@ cdef class Aligner:
cdef cmappy.mm_idxopt_t idx_opt
cdef cmappy.mm_mapopt_t map_opt
def __cinit__(self, fn_idx_in, 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):
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
if preset is not None:
cmappy.mm_set_opt(str.encode(preset), &self.idx_opt, &self.map_opt) # apply preset
@@ -116,17 +127,32 @@ cdef class Aligner:
if bw is not None: self.map_opt.bw = bw
if best_n is not None: self.map_opt.best_n = best_n
if max_frag_len is not None: self.map_opt.max_frag_len = max_frag_len
if extra_flags is not None: self.map_opt.flag |= extra_flags
if scoring is not None and len(scoring) >= 4:
self.map_opt.a, self.map_opt.b = scoring[0], scoring[1]
self.map_opt.q, self.map_opt.e = scoring[2], scoring[3]
self.map_opt.q2, self.map_opt.e2 = self.map_opt.q, self.map_opt.e
if len(scoring) >= 6:
self.map_opt.q2, self.map_opt.e2 = scoring[4], scoring[5]
if len(scoring) >= 7:
self.map_opt.sc_ambi = scoring[6]
cdef cmappy.mm_idx_reader_t *r;
if fn_idx_out is None:
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, NULL)
if seq is None:
if fn_idx_out is None:
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, NULL)
else:
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, str.encode(fn_idx_out))
if r is not NULL:
self._idx = cmappy.mm_idx_reader_read(r, n_threads) # NB: ONLY read the first part
cmappy.mm_idx_reader_close(r)
cmappy.mm_mapopt_update(&self.map_opt, self._idx)
cmappy.mm_idx_index_name(self._idx)
else:
r = cmappy.mm_idx_reader_open(str.encode(fn_idx_in), &self.idx_opt, fn_idx_out)
if r is not NULL:
self._idx = cmappy.mm_idx_reader_read(r, n_threads) # NB: ONLY read the first part
cmappy.mm_idx_reader_close(r)
self._idx = cmappy.mappy_idx_seq(self.idx_opt.w, self.idx_opt.k, self.idx_opt.flag&1, self.idx_opt.bucket_bits, str.encode(seq), len(seq))
cmappy.mm_mapopt_update(&self.map_opt, self._idx)
cmappy.mm_idx_index_name(self._idx)
self.map_opt.mid_occ = 1000 # don't filter high-occ seeds
def __dealloc__(self):
if self._idx is not NULL:
@@ -135,18 +161,25 @@ cdef class Aligner:
def __bool__(self):
return (self._idx != NULL)
def map(self, seq, seq2=None, buf=None, max_frag_len=None):
def map(self, seq, seq2=None, buf=None, cs=False, MD=False, max_frag_len=None, extra_flags=None):
cdef cmappy.mm_reg1_t *regs
cdef cmappy.mm_hitpy_t h
cdef ThreadBuffer b
cdef int n_regs
cdef char *cs_str = NULL
cdef int l_cs_str, m_cs_str = 0
cdef void *km
cdef cmappy.mm_mapopt_t map_opt
if self._idx == NULL: return
map_opt = self.map_opt
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 self._idx is NULL: return None
if buf is None: b = ThreadBuffer()
else: b = buf
km = cmappy.mm_tbuf_get_km(b._b)
_seq = seq if isinstance(seq, bytes) else seq.encode()
if seq2 is None:
@@ -155,19 +188,36 @@ cdef class Aligner:
_seq2 = seq2 if isinstance(seq2, bytes) else seq2.encode()
regs = cmappy.mm_map_aux(self._idx, _seq, _seq2, &n_regs, b._b, &map_opt)
for i in range(n_regs):
cmappy.mm_reg2hitpy(self._idx, &regs[i], &h)
cigar = []
for k in range(h.n_cigar32):
c = h.cigar32[k]
cigar.append([c>>4, c&0xf])
yield Alignment(h.ctg, h.ctg_len, h.ctg_start, h.ctg_end, h.strand, h.qry_start, h.qry_end, h.mapq, cigar, h.is_primary, h.mlen, h.blen, h.NM, h.trans_strand, h.seg_id)
cmappy.mm_free_reg1(&regs[i])
free(regs)
try:
i = 0
while i < n_regs:
cmappy.mm_reg2hitpy(self._idx, &regs[i], &h)
cigar, _cs, _MD = [], '', ''
for k in range(h.n_cigar32): # convert the 32-bit CIGAR encoding to Python array
c = h.cigar32[k]
cigar.append([c>>4, c&0xf])
if cs or MD: # generate the cs and/or the MD tag, if requested
if cs:
l_cs_str = cmappy.mm_gen_cs(km, &cs_str, &m_cs_str, self._idx, &regs[i], _seq, 1)
_cs = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
if MD:
l_cs_str = cmappy.mm_gen_MD(km, &cs_str, &m_cs_str, self._idx, &regs[i], _seq)
_MD = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode()
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)
cmappy.mm_free_reg1(&regs[i])
i += 1
finally:
while i < n_regs:
cmappy.mm_free_reg1(&regs[i])
i += 1
free(regs)
free(cs_str)
def seq(self, str name, int start=0, int end=0x7fffffff):
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
r = s[:l] if isinstance(s, str) else s[:l].decode()
free(s)
@@ -182,6 +232,17 @@ cdef class Aligner:
@property
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):
cdef cmappy.kseq_t *ks
ks = cmappy.mm_fastx_open(str.encode(fn))
+8 -4
View File
@@ -1,10 +1,11 @@
#!/usr/bin/env python
import sys, getopt
import sys
import getopt
import mappy as mp
def main(argv):
opts, args = getopt.getopt(argv[1:], "x:n:m:k:w:r:")
opts, args = getopt.getopt(argv[1:], "x:n:m:k:w:r:c")
if len(args) < 2:
print("Usage: minimap2.py [options] <ref.fa>|<ref.mmi> <query.fq>")
print("Options:")
@@ -14,9 +15,11 @@ def main(argv):
print(" -k INT k-mer length")
print(" -w INT minimizer window length")
print(" -r INT band width")
print(" -c output the cs tag")
sys.exit(1)
preset, min_cnt, min_sc, k, w, bw = None, None, None, None, None, None
preset = min_cnt = min_sc = k = w = bw = None
out_cs = False
for opt, arg in opts:
if opt == '-x': preset = arg
elif opt == '-n': min_cnt = int(arg)
@@ -24,11 +27,12 @@ def main(argv):
elif opt == '-r': bw = int(arg)
elif opt == '-k': k = int(arg)
elif opt == '-w': w = int(arg)
elif opt == '-c': out_cs = True
a = mp.Aligner(args[0], preset=preset, min_cnt=min_cnt, min_chain_score=min_sc, k=k, w=w, bw=bw)
if not a: raise Exception("ERROR: failed to load/build index file '{}'".format(args[0]))
for name, seq, qual in mp.fastx_read(args[1]): # read one sequence
for h in a.map(seq): # traverse hits
for h in a.map(seq, cs=out_cs): # traverse hits
print('{}\t{}\t{}'.format(name, len(seq), h))
if __name__ == "__main__":
+7 -6
View File
@@ -177,7 +177,7 @@ uint64_t *sdust(void *km, const uint8_t *seq, int l_seq, int T, int W, int *n)
#ifdef _SDUST_MAIN
#include <zlib.h>
#include <stdio.h>
#include "getopt.h"
#include "ketopt.h"
#include "kseq.h"
KSEQ_INIT(gzFile, gzread)
@@ -186,16 +186,17 @@ int main(int argc, char *argv[])
gzFile fp;
kseq_t *ks;
int W = 64, T = 20, c;
ketopt_t o = KETOPT_INIT;
while ((c = getopt(argc, argv, "w:t:")) >= 0) {
if (c == 'w') W = atoi(optarg);
else if (c == 't') T = atoi(optarg);
while ((c = ketopt(&o, argc, argv, 1, "w:t:", 0)) >= 0) {
if (c == 'w') W = atoi(o.arg);
else if (c == 't') T = atoi(o.arg);
}
if (optind == argc) {
if (o.ind == argc) {
fprintf(stderr, "Usage: sdust [-w %d] [-t %d] <in.fa>\n", W, T);
return 1;
}
fp = strcmp(argv[optind], "-")? gzopen(argv[optind], "r") : gzdopen(fileno(stdin), "r");
fp = strcmp(argv[o.ind], "-")? gzopen(argv[o.ind], "r") : gzdopen(fileno(stdin), "r");
ks = kseq_init(fp);
while (kseq_read(ks) >= 0) {
uint64_t *r;
+105
View File
@@ -0,0 +1,105 @@
#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);
//fprintf(stderr, "Y\t%d\t%d\n", ps, pe);
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;
}
+19 -19
View File
@@ -4,26 +4,26 @@ except ImportError:
from distutils.core import setup
from distutils.extension import Extension
cmdclass = {}
import sys, platform
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
sys.path.append('python')
extra_compile_args = ['-DHAVE_KALLOC']
include_dirs = ["."]
if platform.machine() in ["aarch64", "arm64"]:
include_dirs.append("sse2neon/")
extra_compile_args.extend(['-ftree-vectorize', '-DKSW_SSE2_ONLY', '-D__SSE2__'])
else:
extra_compile_args.append('-msse4.1') # WARNING: ancient x86_64 CPUs don't have SSE4
def readme():
with open('python/README.rst') as f:
return f.read()
with open('python/README.rst') as f:
return f.read()
setup(
name = 'mappy',
version = '2.11',
version = '2.20',
url = 'https://github.com/lh3/minimap2',
description = 'Minimap2 python binding',
long_description = readme(),
@@ -32,15 +32,15 @@ setup(
license = 'MIT',
keywords = 'sequence-alignment',
scripts = ['python/minimap2.py'],
ext_modules = [Extension('mappy',
sources = [module_src, 'align.c', 'bseq.c', 'chain.c', 'format.c', 'hit.c', 'index.c', 'pe.c', 'options.c',
ext_modules = [Extension('mappy',
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',
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c'],
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c', 'splitidx.c'],
depends = ['minimap.h', 'bseq.h', 'kalloc.h', 'kdq.h', 'khash.h', 'kseq.h', 'ksort.h',
'ksw2.h', 'kthread.h', 'kvec.h', 'mmpriv.h', 'sdust.h',
'python/cmappy.h', 'python/cmappy.pxd'],
extra_compile_args = ['-DHAVE_KALLOC', '-msse4.1'], # WARNING: ancient x86_64 CPUs don't have SSE4
include_dirs = ['.'],
extra_compile_args = extra_compile_args,
include_dirs = include_dirs,
libraries = ['z', 'm', 'pthread'])],
classifiers = [
'Development Status :: 5 - Production/Stable',
@@ -52,4 +52,4 @@ setup(
'Programming Language :: Python :: 3',
'Intended Audience :: Science/Research',
'Topic :: Scientific/Engineering :: Bio-Informatics'],
cmdclass = cmdclass)
setup_requires=["cython"])
+84
View File
@@ -0,0 +1,84 @@
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "mmpriv.h"
FILE *mm_split_init(const char *prefix, const mm_idx_t *mi)
{
char *fn;
FILE *fp;
uint32_t i, k = mi->k;
fn = (char*)calloc(strlen(prefix) + 10, 1);
sprintf(fn, "%s.%.4d.tmp", prefix, mi->index);
if ((fp = fopen(fn, "wb")) == NULL) {
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(&mi->n_seq, 4, 1, fp);
for (i = 0; i < mi->n_seq; ++i) {
uint32_t l;
l = strlen(mi->seq[i].name);
mm_err_fwrite(&l, 1, 4, fp);
mm_err_fwrite(mi->seq[i].name, 1, l, fp);
mm_err_fwrite(&mi->seq[i].len, 4, 1, fp);
}
free(fn);
return fp;
}
mm_idx_t *mm_split_merge_prep(const char *prefix, int n_splits, FILE **fp, uint32_t *n_seq_part)
{
mm_idx_t *mi = 0;
char *fn;
int i, j;
if (n_splits < 1) return 0;
fn = CALLOC(char, strlen(prefix) + 10);
for (i = 0; i < n_splits; ++i) {
sprintf(fn, "%s.%.4d.tmp", prefix, i);
if ((fp[i] = fopen(fn, "rb")) == 0) {
if (mm_verbose >= 1)
fprintf(stderr, "ERROR: failed to open temporary file '%s': %s\n", fn, strerror(errno));
for (j = 0; j < i; ++j)
fclose(fp[j]);
free(fn);
return 0;
}
}
free(fn);
mi = CALLOC(mm_idx_t, 1);
for (i = 0; i < n_splits; ++i) {
mm_err_fread(&mi->k, 4, 1, fp[i]); // TODO: check if k is all the same
mm_err_fread(&n_seq_part[i], 4, 1, fp[i]);
mi->n_seq += n_seq_part[i];
}
mi->seq = CALLOC(mm_idx_seq_t, mi->n_seq);
for (i = j = 0; i < n_splits; ++i) {
uint32_t k;
for (k = 0; k < n_seq_part[i]; ++k, ++j) {
uint32_t l;
mm_err_fread(&l, 1, 4, fp[i]);
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].len, 4, 1, fp[i]);
}
}
return mi;
}
void mm_split_rm_tmp(const char *prefix, int n_splits)
{
int i;
char *fn;
fn = CALLOC(char, strlen(prefix) + 10);
for (i = 0; i < n_splits; ++i) {
sprintf(fn, "%s.%.4d.tmp", prefix, i);
remove(fn);
}
free(fn);
}