Compare commits

..
45 Commits
Author SHA1 Message Date
Heng Li eb819c29e8 Release minimap2-2.6 (r623) 2017-12-12 11:09:59 -05:00
Heng Li fb630de40a r622: fixed bug in sdust due to recent refactor 2017-12-11 15:32:28 -05:00
Heng Li 43960a8ca7 r621: --print-qname also shows kalloc status 2017-12-11 12:30:08 -05:00
Heng Li f6608fe99c r620: revamped thread-local memory management
* Don't preallocate sdust_buf or minizer list. kalloc should be fast enough -
  benchmarks needed to confirm.

* Fixed a memory leak caused by divergence estimate (post v2.5)

* Reset the kalloc buffer after mapping a long query. This reduces peak memory
  when large chunks of memory are allocated, at the cost of performance, though.
2017-12-11 12:11:10 -05:00
Heng Li 98a6e52c06 r618: heuristics to avoid tiny terminal exons 2017-12-11 00:57:55 -05:00
Heng Li 824712a4ee r617: removed some unused code 2017-12-10 17:54:50 -05:00
Heng Li 0e42628ef6 r611: document --idx-no-seq; better inv aln 2017-12-08 13:16:18 -05:00
Heng Li 98a999fe44 r611: added pseudocount when est divergence 2017-12-08 12:57:57 -05:00
Heng Li fec7bd713f r610: warning if db sequence is 0-lengthed (#69) 2017-12-07 21:05:39 -05:00
Heng Li 2f693e8ca4 r609: bugfix - SDUST masking not working 2017-12-07 11:45:38 -05:00
Heng Li 704ff9f4c6 r607: estimate sequence divergence
Currently using the simplest method. There may be a more accurate estimate.
2017-12-06 16:14:39 -05:00
Heng Li 68c63f2d68 r606: fixed a sketch bug for long 256bp k-mer
sketch() writes {-1,-1} to the output array.
2017-12-06 16:13:29 -05:00
Heng Li 76206f574f support both SAM and PAF as input 2017-12-02 21:57:19 -05:00
Heng Li e575f884e1 convert spliced PAF to BED 2017-12-02 21:23:41 -05:00
Heng Li 571161d5a2 changed badges 2017-12-01 16:16:27 -05:00
Heng Li 07d41efc2b explain secondary/supplementary aln for RNA-seq 2017-11-30 23:02:20 -05:00
Heng Li 984f7846c0 r601: bugfix - a similar issue to r600
This bug unsets the alignment score of suboptimal alignments.
2017-11-30 11:51:34 -05:00
Heng Li af1d6afba9 r600: bugfix - missing secondary alignments (#71)
This should very rarely happen to typical data, but has a higher chance in
artifactual data.
2017-11-30 11:34:10 -05:00
Heng Li cbdb6c069f when there are incorrect anno, warn but not abort 2017-11-24 12:48:49 -05:00
Heng Li 35b6d9f7d5 direct manpage to HTML 2017-11-24 11:05:20 -05:00
Heng Li 39a9666246 convert PAF to LAST's cigar output
also added the support of BLAST-like output for "--cs=short".
2017-11-18 20:30:44 -05:00
Heng Li 662d05dc02 fixed incorrect var coordinate 2017-11-12 20:25:33 -05:00
Heng Li 379457c18b use mapq threshold 2017-11-12 19:01:34 -05:00
Heng Li 03169d590b print cov-1 regions (not BED output any more) 2017-11-12 18:45:49 -05:00
Heng Li 8c8d446820 find regions covered by one contig 2017-11-12 18:41:01 -05:00
Heng Li 0ddb064f17 dnadiff-like script; improvement coming 2017-11-12 15:07:29 -05:00
Heng Li 131cfc6938 r574: build index without sequences 2017-11-11 21:38:38 -05:00
Heng Li 2f463b1db0 r573: prepare to generalize index 2017-11-11 19:54:06 -05:00
Heng Li 3b518271ee Release minimap2-2.5 (r572) 2017-11-11 11:29:28 -05:00
Heng Li 481d8239e9 Merge pull request #57 from cjw85/strand_typo
Fix typo in strand property
2017-11-10 20:36:19 -05:00
cwright 4f77b0c1ed Fix typo in strand property 2017-11-11 01:18:44 +00:00
Heng Li d7a31e40e6 r569: last commit is buggy 2017-11-09 23:20:41 -05:00
Heng Li dd18cd75de r568: revert - don't take max(dp_max, dp_score) 2017-11-09 23:12:48 -05:00
Heng Li 99a2709913 r567: minor change to #56 2017-11-09 19:17:45 -05:00
Heng Li 032068a747 Merge pull request #56 from mvdbeek/softclipping
Implement -Y for soft clipping of supp. alignments
2017-11-09 19:12:47 -05:00
mvdbeek 1cb0bf4bef Implement -Y for soft clipping of supp. alignments
I tried to base this on bwa-mem and it seems to work for sam alignments.
2017-11-09 19:22:36 +01:00
Heng Li 422b43374e Merge pull request #55 from martinghunt/fix_python3_strings
Bug fix with byte strings in Python3
2017-11-09 09:37:41 -05:00
martinghunt 29a26e3eea Bug fix with byte strings in Python3 2017-11-09 13:57:15 +00:00
Heng Li a7b38f6900 r562: fixed a severe bug: wrong query start 2017-11-08 22:31:05 -05:00
Heng Li e896c9ec05 r559: prefer a chain involving more segments 2017-11-08 13:22:16 -05:00
Heng Li 98ba8928c6 r558: dp_max no less than dp_score 2017-11-08 10:06:10 -05:00
Heng Li bcf8462d20 Merge pull request #52 from cvdelannoy/patch-1
Update README.md
2017-11-08 07:50:31 -05:00
Carlos de Lannoy c047c852ce Update README.md
25: changed -x ava-one to -x ava-ont
2017-11-08 13:07:01 +01:00
Heng Li b24d68ae9f r557: fixed another mapq underestimate
When a chain is split during base-level alignment, its chaining score is
reduced. However, the chaining score of its suboptimal chain remains the same.
This leads to underestimated mapping quality.
2017-11-07 23:20:49 -05:00
Heng Li 65deedfa96 r556: bugfix - underestimate mapq for split aln 2017-11-07 22:37:12 -05:00
25 changed files with 818 additions and 209 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
CFLAGS= -g -Wall -O2 -Wc++-compat CFLAGS= -g -Wall -O2 -Wc++-compat
CPPFLAGS= -DHAVE_KALLOC CPPFLAGS= -DHAVE_KALLOC
INCLUDES= INCLUDES=
OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o index.o chain.o align.o hit.o map.o format.o pe.o ksw2_ll_sse.o OBJS= kthread.o kalloc.o misc.o bseq.o sketch.o sdust.o index.o chain.o align.o hit.o map.o format.o pe.o esterr.o ksw2_ll_sse.o
PROG= minimap2 PROG= minimap2
PROG_EXTRA= sdust minimap2-lite PROG_EXTRA= sdust minimap2-lite
LIBS= -lm -lz -lpthread LIBS= -lm -lz -lpthread
+55
View File
@@ -1,3 +1,58 @@
Release 2.6-r623 (12 December 2017)
-----------------------------------
This release adds several features and fixes two minor bugs:
* Optionally build an index without sequences. This helps to reduce the
peak memory for read overlapping and is automatically applied when
base-level alignment is not requested.
* Approximately estimate per-base sequence divergence (i.e. 1-identity)
without performing base-level alignment, using a MashMap-like method. The
estimate is written to a new dv:f tag.
* Reduced the number of tiny terminal exons in RNA-seq alignment. The current
setting is conservative. Increase --end-seed-pen to drop more such exons.
* Reduced the peak memory when aligning long query sequences.
* Fixed a bug that is caused by HPC minimizers longer than 256bp. This should
have no effect in practice, but it is recommended to rebuild HPC indices if
possible.
* Fixed a bug when identifying identical hits (#71). This should only affect
artifactual reference consisting of near identical sequences.
For genomic sequences, minimap2 should give nearly identical alignments to
v2.5, except the new dv:f tag.
(2.6: 12 December 2017, r623)
Release 2.5-r572 (11 November 2017)
-----------------------------------
This release fixes several bugs and brings a couple of minor improvements:
* Fixed a severe bug that leads to incorrect mapping coordinates in rare
corner cases.
* Fixed underestimated mapping quality for chimeric alignments when the whole
query sequence contain many repetitive minimizers, and for chimeric
alignments caused by Z-drop.
* Fixed two bugs in Python binding: incorrect strand field (#57) and incorrect
sequence names for Python3 (#55).
* Improved mapping accuracy for highly overlapping paired ends.
* Added option -Y to use soft clipping for supplementary alignments (#56).
(2.5: 11 November 2017, r572)
Release 2.4-r555 (6 November 2017) Release 2.4-r555 (6 November 2017)
---------------------------------- ----------------------------------
+21 -9
View File
@@ -1,10 +1,7 @@
[![Release](https://img.shields.io/badge/Release-v2.4-blue.svg?style=flat)](https://github.com/lh3/minimap2/releases) [![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](https://img.shields.io/conda/vn/bioconda/minimap2.svg?style=flat)](https://anaconda.org/bioconda/minimap2) [![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) [![PyPI](https://img.shields.io/pypi/v/mappy.svg?style=flat)](https://pypi.python.org/pypi/mappy)
[![Python Version](https://img.shields.io/pypi/pyversions/mappy.svg?style=flat)](https://pypi.python.org/pypi/mappy)
[![License](https://img.shields.io/badge/License-MIT-blue.svg?style=flat)](LICENSE.txt)
[![Build Status](https://travis-ci.org/lh3/minimap2.svg?branch=master)](https://travis-ci.org/lh3/minimap2) [![Build Status](https://travis-ci.org/lh3/minimap2.svg?branch=master)](https://travis-ci.org/lh3/minimap2)
[![Downloads](https://img.shields.io/github/downloads/lh3/minimap2/total.svg?style=flat)](https://github.com/lh3/minimap2/releases)
## <a name="started"></a>Getting Started ## <a name="started"></a>Getting Started
```sh ```sh
git clone https://github.com/lh3/minimap2 git clone https://github.com/lh3/minimap2
@@ -22,7 +19,7 @@ cd minimap2 && make
./minimap2 -ax splice -k14 -uf ref.fa reads.fa > aln.sam # Nanopore Direct RNA-seq ./minimap2 -ax splice -k14 -uf ref.fa reads.fa > aln.sam # Nanopore Direct RNA-seq
./minimap2 -cx asm5 asm1.fa asm2.fa > aln.paf # intra-species asm-to-asm alignment ./minimap2 -cx asm5 asm1.fa asm2.fa > aln.paf # intra-species asm-to-asm alignment
./minimap2 -x ava-pb reads.fa reads.fa > overlaps.paf # PacBio read overlap ./minimap2 -x ava-pb reads.fa reads.fa > overlaps.paf # PacBio read overlap
./minimap2 -x ava-one reads.fa reads.fa > overlaps.paf # Nanopore read overlap ./minimap2 -x ava-ont reads.fa reads.fa > overlaps.paf # Nanopore read overlap
# man page for detailed command line options # man page for detailed command line options
man ./minimap2.1 man ./minimap2.1
``` ```
@@ -71,9 +68,9 @@ Detailed evaluations are available from the [minimap2 preprint][preprint].
Minimap2 only works on x86-64 CPUs. You can acquire precompiled binaries from Minimap2 only works on x86-64 CPUs. You can acquire precompiled binaries from
the [release page][release] with: the [release page][release] with:
```sh ```sh
wget --no-check-certificate -O- https://github.com/lh3/minimap2/releases/download/v2.4/minimap2-2.4_x64-linux.tar.bz2 \ curl -L https://github.com/lh3/minimap2/releases/download/v2.6/minimap2-2.6_x64-linux.tar.bz2 \
| tar -jxvf - | tar -jxvf -
./minimap2-2.4_x64-linux/minimap2 ./minimap2-2.6_x64-linux/minimap2
``` ```
If you want to compile from the source, you need to have a C compiler, GNU make If you want to compile from the source, you need to have a C compiler, GNU make
and zlib development files installed. Then type `make` in the source code and zlib development files installed. Then type `make` in the source code
@@ -154,6 +151,20 @@ slight improvement to accuracy. For noisy Nanopore Direct RNA-seq reads, it is
recommended to use a smaller k-mer size for increased sensitivity to the first recommended to use a smaller k-mer size for increased sensitivity to the first
or the last exons. or the last exons.
Minimap2 rates an alignment by the score of the max-scoring sub-segment,
*excluding* introns, and marks the best alignment as primary in SAM. When a
spliced gene also has unspliced pseudogenes, minimap2 does not intentionally
prefer spliced alignment, though in practice it more often marks the spliced
alignment as the primary. By default, minimap2 outputs up to five secondary
alignments (i.e. likely pseudogenes in the context of RNA-seq mapping). This
can be tuned with option **-N**.
For long RNA-seq reads, minimap2 may produce chimeric alignments potentially
caused by gene fusions/structural variations or by an intron longer than the
max intron length **-G** (200k by default). For now, it is not recommended to
apply an excessively large **-G** as this slows down minimap2 and sometimes
leads to false alignments.
It is worth noting that by default `-x splice` prefers GT[A/G]..[C/T]AG It is worth noting that by default `-x splice` prefers GT[A/G]..[C/T]AG
over GT[C/T]..[A/G]AG, and then over other splicing signals. Considering over GT[C/T]..[A/G]AG, and then over other splicing signals. Considering
one additional base improves the junction accuracy for noisy reads, but one additional base improves the junction accuracy for noisy reads, but
@@ -309,7 +320,7 @@ highlighted in bold. The description may help to tune minimap2 parameters.
### <a name="help"></a>Getting help ### <a name="help"></a>Getting help
Manpage [minimap2.1](minimap2.1) provides detailed description of minimap2 Manpage [minimap2.1][manpage] provides detailed description of minimap2
command line options and optional tags. If you encounter bugs or have further command line options and optional tags. If you encounter bugs or have further
questions or requests, you can raise an issue at the [issue page][issue]. questions or requests, you can raise an issue at the [issue page][issue].
There is not a specific mailing list for the time being. There is not a specific mailing list for the time being.
@@ -363,3 +374,4 @@ warmly welcomed.
[mappyconda]: https://anaconda.org/bioconda/mappy [mappyconda]: https://anaconda.org/bioconda/mappy
[issue]: https://github.com/lh3/minimap2/issues [issue]: https://github.com/lh3/minimap2/issues
[k8]: https://github.com/attractivechaos/k8 [k8]: https://github.com/attractivechaos/k8
[manpage]: https://lh3.github.io/minimap2/minimap2.html
+69 -28
View File
@@ -1,6 +1,7 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h>
#include "minimap.h" #include "minimap.h"
#include "mmpriv.h" #include "mmpriv.h"
#include "ksw2.h" #include "ksw2.h"
@@ -110,14 +111,17 @@ static void mm_fix_cigar(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *tseq,
} }
if ((p->cigar[0]&0xf) == 1 || (p->cigar[0]&0xf) == 2) { // get rid of leading I or D if ((p->cigar[0]&0xf) == 1 || (p->cigar[0]&0xf) == 2) { // get rid of leading I or D
int32_t l = p->cigar[0] >> 4; int32_t l = p->cigar[0] >> 4;
if ((p->cigar[0]&0xf) == 1) r->qs += l, *qshift = l; if ((p->cigar[0]&0xf) == 1) {
else r->rs += l, *tshift = l; if (r->rev) r->qe -= l;
else r->qs += l;
*qshift = l;
} else r->rs += l, *tshift = l;
--p->n_cigar; --p->n_cigar;
memmove(p->cigar, p->cigar + 1, p->n_cigar * 4); memmove(p->cigar, p->cigar + 1, p->n_cigar * 4);
} }
} }
static void mm_update_extra(mm_reg1_t *r, const uint8_t *qseq, const uint8_t *qual, const uint8_t *tseq, const int8_t *mat, int8_t q, int8_t e) 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, toff = 0, qoff = 0; uint32_t k, l, toff = 0, qoff = 0;
int32_t s = 0, max = 0, qshift, tshift; int32_t s = 0, max = 0, qshift, tshift;
@@ -219,7 +223,7 @@ static inline int mm_get_hplen_back(const mm_idx_t *mi, uint32_t rid, uint32_t x
static inline void mm_adjust_minier(const mm_idx_t *mi, uint8_t *const qseq0[2], mm128_t *a, int32_t *r, int32_t *q) static inline void mm_adjust_minier(const mm_idx_t *mi, uint8_t *const qseq0[2], mm128_t *a, int32_t *r, int32_t *q)
{ {
if (mi->is_hpc) { if (mi->flag & MM_I_HPC) {
const uint8_t *qseq = qseq0[a->x>>63]; const uint8_t *qseq = qseq0[a->x>>63];
int i, c; int i, c;
*q = (int32_t)a->y; *q = (int32_t)a->y;
@@ -338,7 +342,49 @@ static void mm_max_stretch(const mm_mapopt_t *opt, const mm_reg1_t *r, const mm1
*as = max_i, *cnt = max_len; *as = max_i, *cnt = max_len;
} }
static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], uint8_t *qual0[2], mm_reg1_t *r, mm_reg1_t *r2, int n_a, mm128_t *a, ksw_extz_t *ez, int splice_flag) static int mm_seed_ext_score(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, const int8_t mat[25], int qlen, uint8_t *qseq0[2], const mm128_t *a)
{
uint8_t *qseq, *tseq;
int q_span = a->y>>32&0xff, qs, qe, rs, re, rid, score, q_off, t_off, ext_len = opt->anchor_ext_len;
void *qp;
rid = a->x<<1>>33;
re = (uint32_t)a->x + 1, rs = re - q_span;
qe = (uint32_t)a->y + 1, qs = qe - q_span;
rs = rs - ext_len > 0? rs - ext_len : 0;
qs = qs - ext_len > 0? qs - ext_len : 0;
re = re + ext_len < mi->seq[rid].len? re + ext_len : mi->seq[rid].len;
qe = qe + ext_len < qlen? qe + ext_len : qlen;
tseq = (uint8_t*)kmalloc(km, re - rs);
mm_idx_getseq(mi, rid, rs, re, tseq);
qseq = qseq0[a->x>>63] + qs;
qp = ksw_ll_qinit(km, 2, qe - qs, qseq, 5, mat);
score = ksw_ll_i16(qp, re - rs, tseq, opt->q, opt->e, &q_off, &t_off);
kfree(km, tseq);
kfree(km, qp);
return score;
}
static void mm_fix_bad_ends_splice(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, const mm_reg1_t *r, const int8_t mat[25], int qlen, uint8_t *qseq0[2], const mm128_t *a, int *as1, int *cnt1)
{ // this assumes a very crude k-mer based mode; it is not necessary to use a good model just for filtering bounary exons
int score;
double log_gap;
*as1 = r->as, *cnt1 = r->cnt;
if (r->cnt < 3) return;
log_gap = log((int32_t)a[r->as + 1].x - (int32_t)a[r->as].x);
if ((a[r->as].y>>32&0xff) < log_gap + opt->anchor_ext_shift) {
score = mm_seed_ext_score(km, opt, mi, mat, qlen, qseq0, &a[r->as]);
if ((double)score / mat[0] < log_gap + opt->anchor_ext_shift) // a more exact format is "score < log_4(gap) + shift"
++(*as1), --(*cnt1);
}
log_gap = log((int32_t)a[r->as + r->cnt - 1].x - (int32_t)a[r->as + r->cnt - 2].x);
if ((a[r->as + r->cnt - 1].y>>32&0xff) < log_gap + opt->anchor_ext_shift) {
score = mm_seed_ext_score(km, opt, mi, mat, qlen, qseq0, &a[r->as + r->cnt - 1]);
if ((double)score / mat[0] < log_gap + opt->anchor_ext_shift)
--(*cnt1);
}
}
static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], mm_reg1_t *r, mm_reg1_t *r2, int n_a, mm128_t *a, ksw_extz_t *ez, int splice_flag)
{ {
int is_sr = !!(opt->flag & MM_F_SR), is_splice = !!(opt->flag & MM_F_SPLICE); int is_sr = !!(opt->flag & MM_F_SR), is_splice = !!(opt->flag & MM_F_SPLICE);
int32_t rid = a[r->as].x<<1>>33, rev = a[r->as].x>>63, as1, cnt1; int32_t rid = a[r->as].x<<1>>33, rev = a[r->as].x>>63, as1, cnt1;
@@ -348,23 +394,25 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
int32_t rs1, qs1, re1, qe1; int32_t rs1, qs1, re1, qe1;
int8_t mat[25]; int8_t mat[25];
if (is_sr) assert(!mi->is_hpc); // HPC won't work with SR because with HPC we can't easily tell if there is a gap if (is_sr) assert(!(mi->flag & MM_I_HPC)); // HPC won't work with SR because with HPC we can't easily tell if there is a gap
r2->cnt = 0; r2->cnt = 0;
if (r->cnt == 0) return; if (r->cnt == 0) return;
ksw_gen_simple_mat(5, mat, opt->a, opt->b); ksw_gen_simple_mat(5, mat, opt->a, opt->b);
bw = (int)(opt->bw * 1.5 + 1.); bw = (int)(opt->bw * 1.5 + 1.);
if (is_sr && !mi->is_hpc) { if (is_sr && !(mi->flag & MM_I_HPC)) {
mm_max_stretch(opt, r, a, &as1, &cnt1); mm_max_stretch(opt, r, a, &as1, &cnt1);
rs = (int32_t)a[as1].x + 1 - (int32_t)(a[as1].y>>32&0xff); rs = (int32_t)a[as1].x + 1 - (int32_t)(a[as1].y>>32&0xff);
qs = (int32_t)a[as1].y + 1 - (int32_t)(a[as1].y>>32&0xff); qs = (int32_t)a[as1].y + 1 - (int32_t)(a[as1].y>>32&0xff);
re = (int32_t)a[as1+cnt1-1].x + 1; re = (int32_t)a[as1+cnt1-1].x + 1;
qe = (int32_t)a[as1+cnt1-1].y + 1; qe = (int32_t)a[as1+cnt1-1].y + 1;
} else { } else {
if (!is_splice) 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, &as1, &cnt1); mm_fix_bad_ends(r, a, opt->bw, &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(km, as1, cnt1, a, 10, 40, opt->max_gap>>1, 10);
mm_adjust_minier(mi, qseq0, &a[as1], &rs, &qs); mm_adjust_minier(mi, qseq0, &a[as1], &rs, &qs);
mm_adjust_minier(mi, qseq0, &a[as1 + cnt1 - 1], &re, &qe); mm_adjust_minier(mi, qseq0, &a[as1 + cnt1 - 1], &re, &qe);
@@ -467,7 +515,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
for (i = is_sr? cnt1 - 1 : 1; i < cnt1; ++i) { // gap filling for (i = is_sr? cnt1 - 1 : 1; i < cnt1; ++i) { // gap filling
if ((a[as1+i].y & (MM_SEED_IGNORE|MM_SEED_TANDEM)) && i != cnt1 - 1) continue; if ((a[as1+i].y & (MM_SEED_IGNORE|MM_SEED_TANDEM)) && i != cnt1 - 1) continue;
if (is_sr && !mi->is_hpc) { if (is_sr && !(mi->flag & MM_I_HPC)) {
re = (int32_t)a[as1 + i].x + 1; re = (int32_t)a[as1 + i].x + 1;
qe = (int32_t)a[as1 + i].y + 1; qe = (int32_t)a[as1 + i].y + 1;
} else mm_adjust_minier(mi, qseq0, &a[as1 + i], &re, &qe); } else mm_adjust_minier(mi, qseq0, &a[as1 + i], &re, &qe);
@@ -530,7 +578,7 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
assert(re1 - rs1 <= re0 - rs0); assert(re1 - rs1 <= re0 - rs0);
if (r->p) { if (r->p) {
mm_idx_getseq(mi, rid, rs1, re1, tseq); mm_idx_getseq(mi, rid, rs1, re1, tseq);
mm_update_extra(r, &qseq0[r->rev][qs1], qual0[r->rev]? &qual0[r->rev][qs1] : 0, tseq, mat, opt->q, opt->e); mm_update_extra(r, &qseq0[r->rev][qs1], tseq, mat, opt->q, opt->e);
if (rev && r->p->trans_strand) if (rev && r->p->trans_strand)
r->p->trans_strand ^= 3; // flip to the read strand r->p->trans_strand ^= 3; // flip to the read strand
} }
@@ -538,10 +586,10 @@ static void mm_align1(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int
kfree(km, tseq); kfree(km, tseq);
} }
static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], uint8_t *qual0[2], const mm_reg1_t *r1, const mm_reg1_t *r2, mm_reg1_t *r_inv, ksw_extz_t *ez) static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, uint8_t *qseq0[2], const mm_reg1_t *r1, const mm_reg1_t *r2, mm_reg1_t *r_inv, ksw_extz_t *ez)
{ {
int tl, ql, score, ret = 0, q_off, t_off; int tl, ql, score, ret = 0, q_off, t_off;
uint8_t *tseq, *qseq, *qual; uint8_t *tseq, *qseq;
int8_t mat[25]; int8_t mat[25];
void *qp; void *qp;
@@ -559,7 +607,6 @@ static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, i
tseq = (uint8_t*)kmalloc(km, tl); tseq = (uint8_t*)kmalloc(km, tl);
mm_idx_getseq(mi, r1->rid, r1->re, r2->rs, tseq); mm_idx_getseq(mi, r1->rid, r1->re, r2->rs, tseq);
qseq = &qseq0[!r1->rev][qlen - r2->qs]; qseq = &qseq0[!r1->rev][qlen - r2->qs];
qual = qual0[!r1->rev]? &qseq0[!r1->rev][qlen - r2->qs] : 0;
mm_seq_rev(ql, qseq); mm_seq_rev(ql, qseq);
mm_seq_rev(tl, tseq); mm_seq_rev(tl, tseq);
@@ -579,9 +626,10 @@ static int mm_align1_inv(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, i
r_inv->inv = 1; r_inv->inv = 1;
r_inv->rev = !r1->rev; r_inv->rev = !r1->rev;
r_inv->rid = r1->rid; r_inv->rid = r1->rid;
r_inv->div = -1.0f;
r_inv->qs = r1->qe + q_off, r_inv->qe = r_inv->qs + ez->max_q + 1; r_inv->qs = r1->qe + q_off, r_inv->qe = r_inv->qs + ez->max_q + 1;
r_inv->rs = r1->re + t_off, r_inv->re = r_inv->rs + ez->max_t + 1; 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], qual? &qual[q_off] : 0, &tseq[t_off], mat, opt->q, opt->e); mm_update_extra(r_inv, &qseq[q_off], &tseq[t_off], mat, opt->q, opt->e);
ret = 1; ret = 1;
end_align1_inv: end_align1_inv:
kfree(km, tseq); kfree(km, tseq);
@@ -598,11 +646,11 @@ static inline mm_reg1_t *mm_insert_reg(const mm_reg1_t *r, int i, int *n_regs, m
return regs; return regs;
} }
mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, const char *qual, int *n_regs_, mm_reg1_t *regs, mm128_t *a) mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a)
{ {
extern unsigned char seq_nt4_table[256]; extern unsigned char seq_nt4_table[256];
int32_t i, n_regs = *n_regs_, n_a; int32_t i, n_regs = *n_regs_, n_a;
uint8_t *qseq0[2], *qual0[2]; uint8_t *qseq0[2];
ksw_extz_t ez; ksw_extz_t ez;
// encode the query sequence // encode the query sequence
@@ -612,12 +660,6 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
qseq0[0][i] = seq_nt4_table[(uint8_t)qstr[i]]; qseq0[0][i] = seq_nt4_table[(uint8_t)qstr[i]];
qseq0[1][qlen - 1 - i] = qseq0[0][i] < 4? 3 - qseq0[0][i] : 4; qseq0[1][qlen - 1 - i] = qseq0[0][i] < 4? 3 - qseq0[0][i] : 4;
} }
if (qual) {
qual0[0] = (uint8_t*)kmalloc(km, qlen * 2);
qual0[1] = qual0[0] + qlen;
for (i = 0; i < qlen; ++i)
qual0[0][i] = qual0[1][qlen - 1 - i] = qual[i] - 33;
} else qual0[0] = qual0[1] = 0;
// align through seed hits // align through seed hits
n_a = mm_squeeze_a(km, n_regs, regs, a); n_a = mm_squeeze_a(km, n_regs, regs, a);
@@ -628,8 +670,8 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
mm_reg1_t s[2], s2[2]; mm_reg1_t s[2], s2[2];
int which, trans_strand; int which, trans_strand;
s[0] = s[1] = regs[i]; s[0] = s[1] = regs[i];
mm_align1(km, opt, mi, qlen, qseq0, qual0, &s[0], &s2[0], n_a, a, &ez, MM_F_SPLICE_FOR); mm_align1(km, opt, mi, qlen, qseq0, &s[0], &s2[0], n_a, a, &ez, MM_F_SPLICE_FOR);
mm_align1(km, opt, mi, qlen, qseq0, qual0, &s[1], &s2[1], n_a, a, &ez, MM_F_SPLICE_REV); mm_align1(km, opt, mi, qlen, qseq0, &s[1], &s2[1], n_a, a, &ez, MM_F_SPLICE_REV);
if (s[0].p->dp_score > s[1].p->dp_score) which = 0, trans_strand = 1; if (s[0].p->dp_score > s[1].p->dp_score) which = 0, trans_strand = 1;
else if (s[0].p->dp_score < s[1].p->dp_score) which = 1, trans_strand = 2; else if (s[0].p->dp_score < s[1].p->dp_score) which = 1, trans_strand = 2;
else trans_strand = 3, which = (qlen + s[0].p->dp_score) & 1; // randomly choose a strand, effectively else trans_strand = 3, which = (qlen + s[0].p->dp_score) & 1; // randomly choose a strand, effectively
@@ -642,13 +684,13 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
} }
regs[i].p->trans_strand = trans_strand; regs[i].p->trans_strand = trans_strand;
} else { // one round of alignment } else { // one round of alignment
mm_align1(km, opt, mi, qlen, qseq0, qual0, &regs[i], &r2, n_a, a, &ez, opt->flag); mm_align1(km, opt, mi, qlen, qseq0, &regs[i], &r2, n_a, a, &ez, opt->flag);
if (opt->flag&MM_F_SPLICE) if (opt->flag&MM_F_SPLICE)
regs[i].p->trans_strand = opt->flag&MM_F_SPLICE_FOR? 1 : 2; regs[i].p->trans_strand = opt->flag&MM_F_SPLICE_FOR? 1 : 2;
} }
if (r2.cnt > 0) regs = mm_insert_reg(&r2, i, &n_regs, regs); if (r2.cnt > 0) regs = mm_insert_reg(&r2, i, &n_regs, regs);
if (!(opt->flag&MM_F_SPLICE) && !(opt->flag&MM_F_SR) && i > 0) { // don't try inversion alignment for -xsplice or -xsr if (!(opt->flag&MM_F_SPLICE) && !(opt->flag&MM_F_SR) && i > 0) { // don't try inversion alignment for -xsplice or -xsr
if (mm_align1_inv(km, opt, mi, qlen, qseq0, qual0, &regs[i-1], &regs[i], &r2, &ez)) { if (mm_align1_inv(km, opt, mi, qlen, qseq0, &regs[i-1], &regs[i], &r2, &ez)) {
regs = mm_insert_reg(&r2, i, &n_regs, regs); regs = mm_insert_reg(&r2, i, &n_regs, regs);
++i; // skip the inserted INV alignment ++i; // skip the inserted INV alignment
} }
@@ -656,7 +698,6 @@ mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *m
} }
*n_regs_ = n_regs; *n_regs_ = n_regs;
kfree(km, qseq0[0]); kfree(km, qseq0[0]);
if (qual0[0]) kfree(km, qual0[0]);
kfree(km, ez.cigar); kfree(km, ez.cigar);
mm_filter_regs(km, opt, n_regs_, regs); mm_filter_regs(km, opt, n_regs_, regs);
mm_hit_sort_by_dp(km, n_regs_, regs); mm_hit_sort_by_dp(km, n_regs_, regs);
+3 -2
View File
@@ -49,7 +49,7 @@ mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int m
int64_t dr = ri - a[j].x; int64_t dr = ri - a[j].x;
int32_t dq = qi - (int32_t)a[j].y, dd, sc, log_dd; 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; int32_t sidj = (a[j].y & MM_SEED_SEG_MASK) >> MM_SEED_SEG_SHIFT;
if (dr == 0 || dq <= 0) continue; 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; if ((sidi == sidj && dq > max_dist_y) || dq > max_dist_x) continue;
dd = dr > dq? dr - dq : dq - dr; dd = dr > dq? dr - dq : dq - dr;
if (sidi == sidj && dd > bw) continue; if (sidi == sidj && dd > bw) continue;
@@ -61,7 +61,8 @@ mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int m
int c_log, c_lin; int c_log, c_lin;
c_lin = (int)(dd * .01 * avg_qspan); c_lin = (int)(dd * .01 * avg_qspan);
c_log = log_dd; c_log = log_dd;
if (dr > dq || sidi != sidj) sc -= c_lin < c_log? c_lin : c_log; 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 -= c_lin + (c_log>>1);
} else sc -= (int)(dd * .01 * avg_qspan) + (log_dd>>1); } else sc -= (int)(dd * .01 * avg_qspan) + (log_dd>>1);
sc += f[j]; sc += f[j];
+64
View File
@@ -0,0 +1,64 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "mmpriv.h"
static inline int32_t get_for_qpos(int32_t qlen, const mm128_t *a)
{
int32_t x = (int32_t)a->y;
int32_t q_span = a->y>>32 & 0xff;
if (a->x>>63)
x = qlen - 1 - (x + 1 - q_span); // revert the position to the forward strand of query
return x;
}
static int get_mini_idx(int qlen, const mm128_t *a, int32_t n, const uint64_t *mini_pos)
{
int32_t x, L = 0, R = n - 1;
x = get_for_qpos(qlen, a);
while (L <= R) { // binary search
int32_t m = ((uint64_t)L + R) >> 1;
int32_t y = (int32_t)mini_pos[m];
if (y < x) L = m + 1;
else if (y > x) R = m - 1;
else return m;
}
return -1;
}
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)
{
int i;
uint64_t sum_k = 0;
float avg_k;
if (n == 0) return;
for (i = 0; i < n; ++i)
sum_k += mini_pos[i] >> 32 & 0xff;
avg_k = (float)sum_k / n;
for (i = 0; i < n_regs; ++i) {
mm_reg1_t *r = &regs[i];
int32_t st, en, j, k, n_match, n_tot, l_ref;
r->div = -1.0f;
if (r->cnt == 0) continue;
st = en = get_mini_idx(qlen, r->rev? &a[r->as + r->cnt - 1] : &a[r->as], n, mini_pos);
if (st < 0) {
if (mm_verbose >= 2)
fprintf(stderr, "[WARNING] logic inconsistency in mm_est_err(). Please contact the developer.\n");
continue;
}
l_ref = mi->seq[r->rid].len;
for (k = 1, j = st + 1, n_match = 1; j < n && k < r->cnt; ++j) {
int32_t x;
x = get_for_qpos(qlen, r->rev? &a[r->as + r->cnt - 1 - k] : &a[r->as + k]);
if (x == (int32_t)mini_pos[j])
++k, en = j, ++n_match;
}
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;
}
}
+16 -10
View File
@@ -202,8 +202,9 @@ static void write_cs(void *km, kstring_t *s, const mm_idx_t *mi, const mm_bseq1_
static inline void write_tags(kstring_t *s, const mm_reg1_t *r) static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
{ {
int type = r->inv? 'I' : r->id == r->parent? 'P' : 'S'; int type;
if (r->iden_flt) mm_sprintf_lite(s, "\tom:i:%d", r->mapq); if (r->id == r->parent) type = r->inv? 'I' : 'P';
else type = r->inv? 'i' : 'S';
if (r->p) { if (r->p) {
mm_sprintf_lite(s, "\tNM:i:%d\tms:i:%d\tAS:i:%d\tnn:i:%d", r->blen - r->mlen + r->p->n_ambi, r->p->dp_max, r->p->dp_score, r->p->n_ambi); mm_sprintf_lite(s, "\tNM:i:%d\tms:i:%d\tAS:i:%d\tnn:i:%d", r->blen - r->mlen + r->p->n_ambi, r->p->dp_max, r->p->dp_score, r->p->n_ambi);
if (r->p->trans_strand == 1 || r->p->trans_strand == 2) if (r->p->trans_strand == 1 || r->p->trans_strand == 2)
@@ -211,6 +212,12 @@ static inline void write_tags(kstring_t *s, const mm_reg1_t *r)
} }
mm_sprintf_lite(s, "\ttp:A:%c\tcm:i:%d\ts1:i:%d", type, r->cnt, r->score); mm_sprintf_lite(s, "\ttp:A:%c\tcm:i:%d\ts1:i:%d", type, r->cnt, r->score);
if (r->parent == r->id) mm_sprintf_lite(s, "\ts2:i:%d", r->subsc); if (r->parent == r->id) mm_sprintf_lite(s, "\ts2:i:%d", r->subsc);
if (r->div >= 0.0f && r->div <= 1.0f) {
char buf[8];
if (r->div == 0.0f) buf[0] = '0', buf[1] = 0;
else sprintf(buf, "%.4f", r->div);
mm_sprintf_lite(s, "\tdv:f:%s", buf);
}
if (r->split) mm_sprintf_lite(s, "\tzd:i:%d", r->split); if (r->split) mm_sprintf_lite(s, "\tzd:i:%d", r->split);
} }
@@ -258,7 +265,7 @@ static inline const mm_reg1_t *get_sam_pri(int n_regs, const mm_reg1_t *regs)
return NULL; return NULL;
} }
static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, const mm_reg1_t *r) static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, const mm_reg1_t *r, int opt_flag)
{ {
if (r->p == 0) { if (r->p == 0) {
mm_sprintf_lite(s, "*"); mm_sprintf_lite(s, "*");
@@ -267,14 +274,14 @@ static void write_sam_cigar(kstring_t *s, int sam_flag, int in_tag, int qlen, co
clip_len[0] = r->rev? qlen - r->qe : r->qs; clip_len[0] = r->rev? qlen - r->qe : r->qs;
clip_len[1] = r->rev? r->qs : qlen - r->qe; clip_len[1] = r->rev? r->qs : qlen - r->qe;
if (in_tag) { if (in_tag) {
int clip_char = (sam_flag&0x800)? 5 : 4; int clip_char = (sam_flag&0x800) && !(opt_flag&MM_F_SOFTCLIP)? 5 : 4;
mm_sprintf_lite(s, "\tCG:B:I"); mm_sprintf_lite(s, "\tCG:B:I");
if (clip_len[0]) mm_sprintf_lite(s, ",%u", clip_len[0]<<4|clip_char); if (clip_len[0]) mm_sprintf_lite(s, ",%u", clip_len[0]<<4|clip_char);
for (k = 0; k < r->p->n_cigar; ++k) for (k = 0; k < r->p->n_cigar; ++k)
mm_sprintf_lite(s, ",%u", r->p->cigar[k]); mm_sprintf_lite(s, ",%u", r->p->cigar[k]);
if (clip_len[1]) mm_sprintf_lite(s, ",%u", clip_len[1]<<4|clip_char); if (clip_len[1]) mm_sprintf_lite(s, ",%u", clip_len[1]<<4|clip_char);
} else { } else {
int clip_char = (sam_flag&0x800)? 'H' : 'S'; int clip_char = (sam_flag&0x800) && !(opt_flag&MM_F_SOFTCLIP)? 'H' : 'S';
if (clip_len[0]) mm_sprintf_lite(s, "%d%c", clip_len[0], clip_char); if (clip_len[0]) mm_sprintf_lite(s, "%d%c", clip_len[0], clip_char);
for (k = 0; k < r->p->n_cigar; ++k) for (k = 0; k < r->p->n_cigar; ++k)
mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, "MIDN"[r->p->cigar[k]&0xf]); mm_sprintf_lite(s, "%d%c", r->p->cigar[k]>>4, "MIDN"[r->p->cigar[k]&0xf]);
@@ -336,9 +343,8 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
mm_sprintf_lite(s, "\t%s\t%d\t0\t*", mi->seq[this_rid].name, this_pos+1); mm_sprintf_lite(s, "\t%s\t%d\t0\t*", mi->seq[this_rid].name, this_pos+1);
} else mm_sprintf_lite(s, "\t*\t0\t0\t*"); } else mm_sprintf_lite(s, "\t*\t0\t0\t*");
} else { } else {
int mapq = !r->iden_flt? r->mapq : r->mapq < 3? r->mapq : 3;
this_rid = r->rid, this_pos = r->rs, this_rev = r->rev; this_rid = r->rid, this_pos = r->rs, this_rev = r->rev;
mm_sprintf_lite(s, "\t%s\t%d\t%d\t", mi->seq[r->rid].name, r->rs+1, mapq); mm_sprintf_lite(s, "\t%s\t%d\t%d\t", mi->seq[r->rid].name, r->rs+1, r->mapq);
if ((opt_flag & MM_F_LONG_CIGAR) && r->p && r->p->n_cigar > max_bam_cigar_op - 2) { if ((opt_flag & MM_F_LONG_CIGAR) && r->p && r->p->n_cigar > max_bam_cigar_op - 2) {
int n_cigar = r->p->n_cigar; int n_cigar = r->p->n_cigar;
if (r->qs != 0) ++n_cigar; if (r->qs != 0) ++n_cigar;
@@ -350,7 +356,7 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
if (flag & 0x100) mm_sprintf_lite(s, "0S"); // secondary alignment 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 if (flag & 0x800) mm_sprintf_lite(s, "%dS", r->re - r->rs); // supplementary alignment
else mm_sprintf_lite(s, "%dS", t->l_seq); else mm_sprintf_lite(s, "%dS", t->l_seq);
} else write_sam_cigar(s, flag, 0, t->l_seq, r); } else write_sam_cigar(s, flag, 0, t->l_seq, r, opt_flag);
} }
// write mate positions // write mate positions
@@ -383,7 +389,7 @@ void mm_write_sam2(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, int se
if (t->qual) sam_write_sq(s, t->qual, t->l_seq, 0, 0); if (t->qual) sam_write_sq(s, t->qual, t->l_seq, 0, 0);
else mm_sprintf_lite(s, "*"); else mm_sprintf_lite(s, "*");
} else { } else {
if ((flag & 0x900) == 0) { if ((flag & 0x900) == 0 || (opt_flag & MM_F_SOFTCLIP)) {
sam_write_sq(s, t->seq, t->l_seq, r->rev, r->rev); sam_write_sq(s, t->seq, t->l_seq, r->rev, r->rev);
mm_sprintf_lite(s, "\t"); mm_sprintf_lite(s, "\t");
if (t->qual) sam_write_sq(s, t->qual, t->l_seq, r->rev, 0); if (t->qual) sam_write_sq(s, t->qual, t->l_seq, r->rev, 0);
@@ -431,7 +437,7 @@ 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)) if (r->p && (opt_flag & MM_F_OUT_CS))
write_cs(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG)); write_cs(km, s, mi, t, r, !(opt_flag&MM_F_OUT_CS_LONG));
if (cigar_in_tag) if (cigar_in_tag)
write_sam_cigar(s, flag, 1, t->l_seq, r); write_sam_cigar(s, flag, 1, t->l_seq, r, opt_flag);
} }
s->s[s->l] = 0; // we always have room for an extra byte (see str_enlarge) s->s[s->l] = 0; // we always have room for an extra byte (see str_enlarge)
+13 -6
View File
@@ -76,10 +76,11 @@ mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u,
mm_reg1_t *ri = &r[i]; mm_reg1_t *ri = &r[i];
ri->id = i; ri->id = i;
ri->parent = MM_PARENT_UNSET; ri->parent = MM_PARENT_UNSET;
ri->score = z[i].x >> 32; ri->score = ri->score0 = z[i].x >> 32;
ri->hash = (uint32_t)z[i].x; ri->hash = (uint32_t)z[i].x;
ri->cnt = (int32_t)z[i].y; ri->cnt = (int32_t)z[i].y;
ri->as = z[i].y >> 32; ri->as = z[i].y >> 32;
ri->div = -1.0f;
mm_reg_set_coor(ri, qlen, a); mm_reg_set_coor(ri, qlen, a);
} }
kfree(km, z); kfree(km, z);
@@ -147,7 +148,7 @@ void mm_set_parent(void *km, float mask_level, int n, mm_reg1_t *r, int sub_diff
ri->parent = rp->parent; ri->parent = rp->parent;
rp->subsc = rp->subsc > ri->score? rp->subsc : ri->score; rp->subsc = rp->subsc > ri->score? rp->subsc : ri->score;
if (ri->cnt >= rp->cnt) cnt_sub = 1; if (ri->cnt >= rp->cnt) cnt_sub = 1;
if (rp->p && ri->p && (rp->rs != ri->rs || rp->re != ri->re || ol != min)) { // the last condition excludes identical hits after DP if (rp->p && ri->p && (rp->rid != ri->rid || rp->rs != ri->rs || rp->re != ri->re || ol != min)) { // the last condition excludes identical hits after DP
rp->p->dp_max2 = rp->p->dp_max2 > ri->p->dp_max? rp->p->dp_max2 : ri->p->dp_max; rp->p->dp_max2 = rp->p->dp_max2 > ri->p->dp_max? rp->p->dp_max2 : ri->p->dp_max;
if (rp->p->dp_max - ri->p->dp_max <= sub_diff) cnt_sub = 1; if (rp->p->dp_max - ri->p->dp_max <= sub_diff) cnt_sub = 1;
} }
@@ -234,7 +235,7 @@ void mm_select_sub(void *km, float pri_ratio, int min_diff, int best_n, int *n_,
if (p == i || r[i].inv) { // primary or inversion if (p == i || r[i].inv) { // primary or inversion
r[k++] = r[i]; r[k++] = r[i];
} else if ((r[i].score >= r[p].score * pri_ratio || r[i].score + min_diff >= r[p].score) && n_2nd < best_n) { } else if ((r[i].score >= r[p].score * pri_ratio || r[i].score + min_diff >= r[p].score) && n_2nd < best_n) {
if (!(r[i].qs == r[p].qs && r[i].qe == r[p].qe && r[i].rs == r[p].rs && r[i].re == r[p].re)) // not identical hits if (!(r[i].qs == r[p].qs && r[i].qe == r[p].qe && r[i].rid == r[p].rid && r[i].rs == r[p].rs && r[i].re == r[p].re)) // not identical hits
r[k++] = r[i], ++n_2nd; r[k++] = r[i], ++n_2nd;
else if (r[i].p) free(r[i].p); else if (r[i].p) free(r[i].p);
} else if (r[i].p) free(r[i].p); } else if (r[i].p) free(r[i].p);
@@ -406,27 +407,33 @@ void mm_seg_free(void *km, int n_segs, mm_seg_t *segs)
void mm_set_mapq(int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr) void mm_set_mapq(int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr)
{ {
static const float q_coef = 40.0f; static const float q_coef = 40.0f;
int64_t sum_sc = 0;
float uniq_ratio;
int i; int i;
for (i = 0; i < n_regs; ++i)
if (regs[i].parent == regs[i].id)
sum_sc += regs[i].score;
uniq_ratio = (float)sum_sc / (sum_sc + rep_len);
for (i = 0; i < n_regs; ++i) { for (i = 0; i < n_regs; ++i) {
mm_reg1_t *r = &regs[i]; mm_reg1_t *r = &regs[i];
if (r->inv) { if (r->inv) {
r->mapq = 0; r->mapq = 0;
} else if (r->parent == r->id) { } else if (r->parent == r->id) {
int mapq, subsc; int mapq, subsc;
float pen_s1 = (r->score > 100? 1.0f : 0.01f * r->score) * ((float)r->score / (r->score + rep_len)); float pen_s1 = (r->score > 100? 1.0f : 0.01f * r->score) * uniq_ratio;
float pen_cm = r->cnt > 10? 1.0f : 0.1f * r->cnt; float pen_cm = r->cnt > 10? 1.0f : 0.1f * r->cnt;
pen_cm = pen_s1 < pen_cm? pen_s1 : pen_cm; pen_cm = pen_s1 < pen_cm? pen_s1 : pen_cm;
subsc = r->subsc > min_chain_sc? r->subsc : min_chain_sc; subsc = r->subsc > min_chain_sc? r->subsc : min_chain_sc;
if (r->p && r->p->dp_max2 > 0 && r->p->dp_max > 0) { if (r->p && r->p->dp_max2 > 0 && r->p->dp_max > 0) {
float identity = (float)r->mlen / r->blen; float identity = (float)r->mlen / r->blen;
float x = (float)r->p->dp_max2 * subsc / r->p->dp_max / r->score; float x = (float)r->p->dp_max2 * subsc / r->p->dp_max / r->score0;
mapq = (int)(identity * pen_cm * q_coef * (1.0f - x * x) * logf((float)r->p->dp_max / match_sc)); mapq = (int)(identity * pen_cm * q_coef * (1.0f - x * x) * logf((float)r->p->dp_max / match_sc));
if (!is_sr) { if (!is_sr) {
int mapq_alt = (int)(6.02f * identity * identity * (r->p->dp_max - r->p->dp_max2) / match_sc + .499f); // BWA-MEM like mapQ, mostly for short reads int mapq_alt = (int)(6.02f * identity * identity * (r->p->dp_max - r->p->dp_max2) / match_sc + .499f); // BWA-MEM like mapQ, mostly for short reads
mapq = mapq < mapq_alt? mapq : mapq_alt; // in case the long-read heuristic fails mapq = mapq < mapq_alt? mapq : mapq_alt; // in case the long-read heuristic fails
} }
} else { } else {
float x = (float)subsc / r->score; float x = (float)subsc / r->score0;
if (r->p) { if (r->p) {
float identity = (float)r->mlen / r->blen; float identity = (float)r->mlen / r->blen;
mapq = (int)(identity * pen_cm * q_coef * (1.0f - x) * logf((float)r->p->dp_max / match_sc)); mapq = (int)(identity * pen_cm * q_coef * (1.0f - x) * logf((float)r->p->dp_max / match_sc));
+39 -30
View File
@@ -31,19 +31,19 @@ typedef struct mm_idx_bucket_s {
void mm_idxopt_init(mm_idxopt_t *opt) void mm_idxopt_init(mm_idxopt_t *opt)
{ {
memset(opt, 0, sizeof(mm_idxopt_t)); memset(opt, 0, sizeof(mm_idxopt_t));
opt->k = 15, opt->w = 10, opt->is_hpc = 0; opt->k = 15, opt->w = 10, opt->flag = 0;
opt->bucket_bits = 14; opt->bucket_bits = 14;
opt->mini_batch_size = 50000000; opt->mini_batch_size = 50000000;
opt->batch_size = 4000000000ULL; opt->batch_size = 4000000000ULL;
} }
mm_idx_t *mm_idx_init(int w, int k, int b, int is_hpc) mm_idx_t *mm_idx_init(int w, int k, int b, int flag)
{ {
mm_idx_t *mi; mm_idx_t *mi;
if (k*2 < b) b = k * 2; if (k*2 < b) b = k * 2;
if (w < 1) w = 1; if (w < 1) w = 1;
mi = (mm_idx_t*)calloc(1, sizeof(mm_idx_t)); mi = (mm_idx_t*)calloc(1, sizeof(mm_idx_t));
mi->w = w, mi->k = k, mi->b = b, mi->is_hpc = is_hpc; mi->w = w, mi->k = k, mi->b = b, mi->flag = flag;
mi->B = (mm_idx_bucket_t*)calloc(1<<b, sizeof(mm_idx_bucket_t)); mi->B = (mm_idx_bucket_t*)calloc(1<<b, sizeof(mm_idx_bucket_t));
if (!(mm_dbg_flag & 1)) mi->km = km_init(); if (!(mm_dbg_flag & 1)) mi->km = km_init();
return mi; return mi;
@@ -89,7 +89,7 @@ void mm_idx_stat(const mm_idx_t *mi)
{ {
int i, n = 0, n1 = 0; int i, n = 0, n1 = 0;
uint64_t sum = 0, len = 0; uint64_t sum = 0, len = 0;
fprintf(stderr, "[M::%s] kmer size: %d; skip: %d; is_HPC: %d; #seq: %d\n", __func__, mi->k, mi->w, mi->is_hpc, mi->n_seq); fprintf(stderr, "[M::%s] kmer size: %d; skip: %d; is_hpc: %d; #seq: %d\n", __func__, mi->k, mi->w, mi->flag&MM_I_HPC, mi->n_seq);
for (i = 0; i < mi->n_seq; ++i) for (i = 0; i < mi->n_seq; ++i)
len += mi->seq[i].len; len += mi->seq[i].len;
for (i = 0; i < 1<<mi->b; ++i) for (i = 0; i < 1<<mi->b; ++i)
@@ -214,7 +214,7 @@ static void mm_idx_post(mm_idx_t *mi, int n_threads)
#include "bseq.h" #include "bseq.h"
typedef struct { typedef struct {
int mini_batch_size, keep_name; int mini_batch_size;
uint64_t batch_size, sum_len; uint64_t batch_size, sum_len;
mm_bseq_file_t *fp; mm_bseq_file_t *fp;
mm_idx_t *mi; mm_idx_t *mi;
@@ -246,7 +246,6 @@ static void *worker_pipeline(void *shared, int step, void *in)
s->seq = mm_bseq_read(p->fp, p->mini_batch_size, 0, &s->n_seq); // read a mini-batch s->seq = mm_bseq_read(p->fp, p->mini_batch_size, 0, &s->n_seq); // read a mini-batch
if (s->seq) { if (s->seq) {
uint32_t old_m, m; uint32_t old_m, m;
uint64_t sum_len, old_max_len, max_len;
assert((uint64_t)p->mi->n_seq + s->n_seq <= UINT32_MAX); // to prevent integer overflow assert((uint64_t)p->mi->n_seq + s->n_seq <= UINT32_MAX); // to prevent integer overflow
// make room for p->mi->seq // make room for p->mi->seq
old_m = p->mi->n_seq, m = p->mi->n_seq + s->n_seq; old_m = p->mi->n_seq, m = p->mi->n_seq + s->n_seq;
@@ -254,29 +253,34 @@ static void *worker_pipeline(void *shared, int step, void *in)
if (old_m != m) if (old_m != m)
p->mi->seq = (mm_idx_seq_t*)krealloc(p->mi->km, p->mi->seq, m * sizeof(mm_idx_seq_t)); p->mi->seq = (mm_idx_seq_t*)krealloc(p->mi->km, p->mi->seq, m * sizeof(mm_idx_seq_t));
// make room for p->mi->S // make room for p->mi->S
for (i = 0, sum_len = 0; i < s->n_seq; ++i) sum_len += s->seq[i].l_seq; if (!(p->mi->flag & MM_I_NO_SEQ)) {
old_max_len = (p->sum_len + 7) / 8; uint64_t sum_len, old_max_len, max_len;
max_len = (p->sum_len + sum_len + 7) / 8; for (i = 0, sum_len = 0; i < s->n_seq; ++i) sum_len += s->seq[i].l_seq;
kroundup64(old_max_len); kroundup64(max_len); old_max_len = (p->sum_len + 7) / 8;
if (old_max_len != max_len) { max_len = (p->sum_len + sum_len + 7) / 8;
p->mi->S = (uint32_t*)realloc(p->mi->S, max_len * 4); kroundup64(old_max_len); kroundup64(max_len);
memset(&p->mi->S[old_max_len], 0, 4 * (max_len - old_max_len)); if (old_max_len != max_len) {
p->mi->S = (uint32_t*)realloc(p->mi->S, max_len * 4);
memset(&p->mi->S[old_max_len], 0, 4 * (max_len - old_max_len));
}
} }
// populate p->mi->seq // populate p->mi->seq
for (i = 0; i < s->n_seq; ++i) { for (i = 0; i < s->n_seq; ++i) {
mm_idx_seq_t *seq = &p->mi->seq[p->mi->n_seq]; mm_idx_seq_t *seq = &p->mi->seq[p->mi->n_seq];
uint32_t j; uint32_t j;
if (p->keep_name) { if (!(p->mi->flag & MM_I_NO_NAME)) {
seq->name = (char*)kmalloc(p->mi->km, strlen(s->seq[i].name) + 1); seq->name = (char*)kmalloc(p->mi->km, strlen(s->seq[i].name) + 1);
strcpy(seq->name, s->seq[i].name); strcpy(seq->name, s->seq[i].name);
} else seq->name = 0; } else seq->name = 0;
seq->len = s->seq[i].l_seq; seq->len = s->seq[i].l_seq;
seq->offset = p->sum_len; seq->offset = p->sum_len;
// copy the sequence // copy the sequence
for (j = 0; j < seq->len; ++j) { // TODO: this is not the fastest way, but let's first see if speed matters here if (!(p->mi->flag & MM_I_NO_SEQ)) {
uint64_t o = p->sum_len + j; for (j = 0; j < seq->len; ++j) { // TODO: this is not the fastest way, but let's first see if speed matters here
int c = seq_nt4_table[(uint8_t)s->seq[i].seq[j]]; uint64_t o = p->sum_len + j;
mm_seq4_set(p->mi->S, o, c); int c = seq_nt4_table[(uint8_t)s->seq[i].seq[j]];
mm_seq4_set(p->mi->S, o, c);
}
} }
// update p->sum_len and p->mi->n_seq // update p->sum_len and p->mi->n_seq
p->sum_len += seq->len; p->sum_len += seq->len;
@@ -288,7 +292,10 @@ static void *worker_pipeline(void *shared, int step, void *in)
step_t *s = (step_t*)in; step_t *s = (step_t*)in;
for (i = 0; i < s->n_seq; ++i) { for (i = 0; i < s->n_seq; ++i) {
mm_bseq1_t *t = &s->seq[i]; mm_bseq1_t *t = &s->seq[i];
mm_sketch(0, t->seq, t->l_seq, p->mi->w, p->mi->k, t->rid, p->mi->is_hpc, &s->a); if (t->l_seq > 0)
mm_sketch(0, t->seq, t->l_seq, p->mi->w, p->mi->k, t->rid, p->mi->flag&MM_I_HPC, &s->a);
else if (mm_verbose >= 2)
fprintf(stderr, "[WARNING] the length database sequence '%s' is 0\n", t->name);
free(t->seq); free(t->name); free(t->seq); free(t->name);
} }
free(s->seq); s->seq = 0; free(s->seq); s->seq = 0;
@@ -301,16 +308,15 @@ static void *worker_pipeline(void *shared, int step, void *in)
return 0; return 0;
} }
mm_idx_t *mm_idx_gen(mm_bseq_file_t *fp, int w, int k, int b, int is_hpc, int mini_batch_size, int n_threads, uint64_t batch_size, int keep_name) mm_idx_t *mm_idx_gen(mm_bseq_file_t *fp, int w, int k, int b, int flag, int mini_batch_size, int n_threads, uint64_t batch_size)
{ {
pipeline_t pl; pipeline_t pl;
if (fp == 0 || mm_bseq_eof(fp)) return 0; if (fp == 0 || mm_bseq_eof(fp)) return 0;
memset(&pl, 0, sizeof(pipeline_t)); memset(&pl, 0, sizeof(pipeline_t));
pl.mini_batch_size = mini_batch_size < batch_size? mini_batch_size : batch_size; pl.mini_batch_size = mini_batch_size < batch_size? mini_batch_size : batch_size;
pl.keep_name = keep_name;
pl.batch_size = batch_size; pl.batch_size = batch_size;
pl.fp = fp; pl.fp = fp;
pl.mi = mm_idx_init(w, k, b, is_hpc); pl.mi = mm_idx_init(w, k, b, flag);
kt_pipeline(n_threads < 3? n_threads : 3, worker_pipeline, &pl, 3); kt_pipeline(n_threads < 3? n_threads : 3, worker_pipeline, &pl, 3);
if (mm_verbose >= 3) if (mm_verbose >= 3)
@@ -323,13 +329,13 @@ mm_idx_t *mm_idx_gen(mm_bseq_file_t *fp, int w, int k, int b, int is_hpc, int mi
return pl.mi; return pl.mi;
} }
mm_idx_t *mm_idx_build(const char *fn, int w, int k, int is_hpc, int n_threads) // a simpler interface mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads) // a simpler interface
{ {
mm_bseq_file_t *fp; mm_bseq_file_t *fp;
mm_idx_t *mi; mm_idx_t *mi;
fp = mm_bseq_open(fn); fp = mm_bseq_open(fn);
if (fp == 0) return 0; if (fp == 0) return 0;
mi = mm_idx_gen(fp, w, k, 14, is_hpc, 1<<18, n_threads, UINT64_MAX, 1); mi = mm_idx_gen(fp, w, k, 14, flag, 1<<18, n_threads, UINT64_MAX);
mm_bseq_close(fp); mm_bseq_close(fp);
return mi; return mi;
} }
@@ -344,7 +350,7 @@ void mm_idx_dump(FILE *fp, const mm_idx_t *mi)
uint32_t x[5]; uint32_t x[5];
int i; int i;
x[0] = mi->w, x[1] = mi->k, x[2] = mi->b, x[3] = mi->n_seq, x[4] = mi->is_hpc; x[0] = mi->w, x[1] = mi->k, x[2] = mi->b, x[3] = mi->n_seq, x[4] = mi->flag;
fwrite(MM_IDX_MAGIC, 1, 4, fp); fwrite(MM_IDX_MAGIC, 1, 4, fp);
fwrite(x, 4, 5, fp); fwrite(x, 4, 5, fp);
for (i = 0; i < mi->n_seq; ++i) { for (i = 0; i < mi->n_seq; ++i) {
@@ -371,7 +377,8 @@ void mm_idx_dump(FILE *fp, const mm_idx_t *mi)
fwrite(x, 8, 2, fp); fwrite(x, 8, 2, fp);
} }
} }
fwrite(mi->S, 4, (sum_len + 7) / 8, fp); if (!(mi->flag & MM_I_NO_SEQ))
fwrite(mi->S, 4, (sum_len + 7) / 8, fp);
fflush(fp); fflush(fp);
} }
@@ -421,8 +428,10 @@ mm_idx_t *mm_idx_load(FILE *fp)
kh_val(h, k) = x[1]; kh_val(h, k) = x[1];
} }
} }
mi->S = (uint32_t*)malloc((sum_len + 7) / 8 * 4); if (!(mi->flag & MM_I_NO_SEQ)) {
fread(mi->S, 4, (sum_len + 7) / 8, fp); mi->S = (uint32_t*)malloc((sum_len + 7) / 8 * 4);
fread(mi->S, 4, (sum_len + 7) / 8, fp);
}
return mi; return mi;
} }
@@ -476,10 +485,10 @@ mm_idx_t *mm_idx_reader_read(mm_idx_reader_t *r, int n_threads)
mm_idx_t *mi; mm_idx_t *mi;
if (r->is_idx) { if (r->is_idx) {
mi = mm_idx_load(r->fp.idx); mi = mm_idx_load(r->fp.idx);
if (mi && mm_verbose >= 2 && (mi->k != r->opt.k || mi->w != r->opt.w || mi->is_hpc != r->opt.is_hpc)) if (mi && mm_verbose >= 2 && (mi->k != r->opt.k || mi->w != r->opt.w || (mi->flag&MM_I_HPC) != (r->opt.flag&MM_I_HPC)))
fprintf(stderr, "[WARNING]\033[1;31m Indexing parameters (-k, -w or -H) overridden by parameters used in the prebuilt index.\033[0m\n"); fprintf(stderr, "[WARNING]\033[1;31m Indexing parameters (-k, -w or -H) overridden by parameters used in the prebuilt index.\033[0m\n");
} else } else
mi = mm_idx_gen(r->fp.seq, r->opt.w, r->opt.k, r->opt.bucket_bits, r->opt.is_hpc, r->opt.mini_batch_size, n_threads, r->opt.batch_size, 1); 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 (mi) {
if (r->fp_out) mm_idx_dump(r->fp_out, mi); if (r->fp_out) mm_idx_dump(r->fp_out, mi);
++r->n_parts; ++r->n_parts;
+6 -2
View File
@@ -189,6 +189,10 @@ void km_stat(const void *_km, km_stat_t *s)
panic("[km_stat] The end of a free block enters another free block."); panic("[km_stat] The end of a free block enters another free block.");
if (p->ptr == km->loop_head) break; if (p->ptr == km->loop_head) break;
} }
for (p = km->core_head; p != NULL; p = p->ptr) for (p = km->core_head; p != NULL; p = p->ptr) {
++s->n_cores, s->capacity += p->size * sizeof(header_t); size_t size = p->size * sizeof(header_t);
++s->n_cores;
s->capacity += size;
s->largest = s->largest > size? s->largest : size;
}
} }
+1 -1
View File
@@ -8,7 +8,7 @@ extern "C" {
#endif #endif
typedef struct { typedef struct {
size_t capacity, available, n_blocks, n_cores; size_t capacity, available, n_blocks, n_cores, largest;
} km_stat_t; } km_stat_t;
void *kmalloc(void *km, size_t size); void *kmalloc(void *km, size_t size);
+17 -2
View File
@@ -6,7 +6,7 @@
#include "mmpriv.h" #include "mmpriv.h"
#include "getopt.h" #include "getopt.h"
#define MM_VERSION "2.4-r555" #define MM_VERSION "2.6-r623"
#ifdef __linux__ #ifdef __linux__
#include <sys/resource.h> #include <sys/resource.h>
@@ -43,6 +43,8 @@ static struct option long_options[] = {
{ "end-bonus", required_argument, 0, 0 }, { "end-bonus", required_argument, 0, 0 },
{ "no-pairing", no_argument, 0, 0 }, { "no-pairing", no_argument, 0, 0 },
{ "splice-flank", optional_argument, 0, 0 }, { "splice-flank", optional_argument, 0, 0 },
{ "idx-no-seq", no_argument, 0, 0 },
{ "end-seed-pen", required_argument, 0, 0 }, // 21
{ "help", no_argument, 0, 'h' }, { "help", no_argument, 0, 'h' },
{ "max-intron-len", required_argument, 0, 'G' }, { "max-intron-len", required_argument, 0, 'G' },
{ "version", no_argument, 0, 'V' }, { "version", no_argument, 0, 'V' },
@@ -94,7 +96,7 @@ int main(int argc, char *argv[])
while ((c = getopt_long(argc, argv, opt_str, long_options, &long_idx)) >= 0) { while ((c = getopt_long(argc, argv, opt_str, long_options, &long_idx)) >= 0) {
if (c == 'w') ipt.w = atoi(optarg); if (c == 'w') ipt.w = atoi(optarg);
else if (c == 'k') ipt.k = atoi(optarg); else if (c == 'k') ipt.k = atoi(optarg);
else if (c == 'H') ipt.is_hpc = 1; 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 == '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 == 'r') opt.bw = (int)mm_parse_num(optarg);
else if (c == 't') n_threads = atoi(optarg); else if (c == 't') n_threads = atoi(optarg);
@@ -109,6 +111,7 @@ int main(int argc, char *argv[])
else if (c == 'X') opt.flag |= MM_F_AVA | MM_F_NO_SELF; else if (c == 'X') opt.flag |= MM_F_AVA | MM_F_NO_SELF;
else if (c == 'a') opt.flag |= MM_F_OUT_SAM | MM_F_CIGAR; else if (c == 'a') opt.flag |= MM_F_OUT_SAM | MM_F_CIGAR;
else if (c == 'Q') opt.flag |= MM_F_NO_QUAL; else if (c == 'Q') opt.flag |= MM_F_NO_QUAL;
else if (c == 'Y') opt.flag |= MM_F_SOFTCLIP;
else if (c == 'L') opt.flag |= MM_F_LONG_CIGAR; else if (c == 'L') opt.flag |= MM_F_LONG_CIGAR;
else if (c == 'T') opt.sdust_thres = atoi(optarg); else if (c == 'T') opt.sdust_thres = atoi(optarg);
else if (c == 'n') opt.min_cnt = atoi(optarg); else if (c == 'n') opt.min_cnt = atoi(optarg);
@@ -137,6 +140,8 @@ int main(int argc, char *argv[])
else if (c == 0 && long_idx ==13) opt.flag |= MM_F_SR; // --sr else if (c == 0 && long_idx ==13) opt.flag |= MM_F_SR; // --sr
else if (c == 0 && long_idx ==17) opt.end_bonus = atoi(optarg); // --end-bonus 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 ==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 == 14) { // --frag else if (c == 0 && long_idx == 14) { // --frag
if (optarg == 0 || strcmp(optarg, "yes") == 0 || strcmp(optarg, "y") == 0) if (optarg == 0 || strcmp(optarg, "yes") == 0 || strcmp(optarg, "y") == 0)
opt.flag |= MM_F_FRAG_MODE; opt.flag |= MM_F_FRAG_MODE;
@@ -195,6 +200,8 @@ int main(int argc, char *argv[])
fprintf(stderr, "[ERROR]\033[1;31m --splice and --frag should not be specified at the same time.\033[0m\n"); fprintf(stderr, "[ERROR]\033[1;31m --splice and --frag should not be specified at the same time.\033[0m\n");
return 1; return 1;
} }
if (!fnw && !(opt.flag&MM_F_CIGAR))
ipt.flag |= MM_I_NO_SEQ;
if (argc == optind || fp_help == stdout) { if (argc == optind || fp_help == stdout) {
fprintf(fp_help, "Usage: minimap2 [options] <target.fa>|<target.idx> [query.fa] [...]\n"); fprintf(fp_help, "Usage: minimap2 [options] <target.fa>|<target.idx> [query.fa] [...]\n");
@@ -232,6 +239,7 @@ int main(int argc, char *argv[])
fprintf(fp_help, " -R STR SAM read group line in a format like '@RG\\tID:foo\\tSM:bar' []\n"); fprintf(fp_help, " -R STR SAM read group line in a format like '@RG\\tID:foo\\tSM:bar' []\n");
fprintf(fp_help, " -c output CIGAR in PAF\n"); fprintf(fp_help, " -c output CIGAR in PAF\n");
fprintf(fp_help, " --cs[=STR] output the cs tag; STR is 'short' (if absent) or 'long' [none]\n"); fprintf(fp_help, " --cs[=STR] output the cs tag; STR is 'short' (if absent) or 'long' [none]\n");
fprintf(fp_help, " -Y use soft clipping for supplementary alignments\n");
fprintf(fp_help, " -t INT number of threads [%d]\n", n_threads); fprintf(fp_help, " -t INT number of threads [%d]\n", n_threads);
fprintf(fp_help, " -K NUM minibatch size for mapping [500M]\n"); fprintf(fp_help, " -K NUM minibatch size for mapping [500M]\n");
// fprintf(fp_help, " -v INT verbose level [%d]\n", mm_verbose); // fprintf(fp_help, " -v INT verbose level [%d]\n", mm_verbose);
@@ -257,11 +265,18 @@ int main(int argc, char *argv[])
} }
if (!idx_rdr->is_idx && fnw == 0 && argc - optind < 2) { if (!idx_rdr->is_idx && fnw == 0 && argc - optind < 2) {
fprintf(stderr, "[ERROR] missing input: please specify a query file to map or option -d to keep the index\n"); 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; return 1;
} }
if (opt.best_n == 0 && (opt.flag&MM_F_CIGAR) && mm_verbose >= 2) if (opt.best_n == 0 && (opt.flag&MM_F_CIGAR) && mm_verbose >= 2)
fprintf(stderr, "[WARNING]\033[1;31m `-N 0' reduces alignment accuracy. Please use --secondary=no to suppress secondary alignments.\033[0m\n"); fprintf(stderr, "[WARNING]\033[1;31m `-N 0' reduces alignment accuracy. Please use --secondary=no to suppress secondary alignments.\033[0m\n");
while ((mi = mm_idx_reader_read(idx_rdr, n_threads)) != 0) { while ((mi = mm_idx_reader_read(idx_rdr, n_threads)) != 0) {
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);
mm_idx_reader_close(idx_rdr);
return 1;
}
if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) { if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) {
if (mm_idx_reader_eof(idx_rdr)) { if (mm_idx_reader_eof(idx_rdr)) {
mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv); mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv);
+65 -49
View File
@@ -36,6 +36,7 @@ void mm_mapopt_init(mm_mapopt_t *opt)
opt->end_bonus = -1; opt->end_bonus = -1;
opt->min_dp_max = opt->min_chain_score * opt->a; opt->min_dp_max = opt->min_chain_score * opt->a;
opt->min_ksw_len = 200; opt->min_ksw_len = 200;
opt->anchor_ext_len = 20, opt->anchor_ext_shift = 6;
opt->mini_batch_size = 500000000; opt->mini_batch_size = 500000000;
opt->pe_ori = 0; // FF opt->pe_ori = 0; // FF
@@ -64,29 +65,29 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
mm_idxopt_init(io); mm_idxopt_init(io);
mm_mapopt_init(mo); mm_mapopt_init(mo);
} else if (strcmp(preset, "ava-ont") == 0) { } else if (strcmp(preset, "ava-ont") == 0) {
io->is_hpc = 0, io->k = 15, io->w = 5; io->flag = 0, io->k = 15, io->w = 5;
mo->flag |= MM_F_AVA | MM_F_NO_SELF; mo->flag |= MM_F_AVA | MM_F_NO_SELF;
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25; mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25;
} else if (strcmp(preset, "ava-pb") == 0) { } else if (strcmp(preset, "ava-pb") == 0) {
io->is_hpc = 1, io->k = 19, io->w = 5; io->flag |= MM_I_HPC, io->k = 19, io->w = 5;
mo->flag |= MM_F_AVA | MM_F_NO_SELF; mo->flag |= MM_F_AVA | MM_F_NO_SELF;
mo->min_chain_score = 100, mo->pri_ratio = 0.0f, mo->max_gap = 10000, mo->max_chain_skip = 25; 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) { } else if (strcmp(preset, "map10k") == 0 || strcmp(preset, "map-pb") == 0) {
io->is_hpc = 1, io->k = 19; io->flag |= MM_I_HPC, io->k = 19;
} else if (strcmp(preset, "map-ont") == 0) { } else if (strcmp(preset, "map-ont") == 0) {
io->is_hpc = 0, io->k = 15; io->flag = 0, io->k = 15;
} else if (strcmp(preset, "asm5") == 0) { } else if (strcmp(preset, "asm5") == 0) {
io->is_hpc = 0, io->k = 19, io->w = 19; io->flag = 0, io->k = 19, io->w = 19;
mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = 200; mo->a = 1, mo->b = 19, mo->q = 39, mo->q2 = 81, mo->e = 3, mo->e2 = 1, mo->zdrop = 200;
mo->min_dp_max = 200; mo->min_dp_max = 200;
mo->best_n = 50; mo->best_n = 50;
} else if (strcmp(preset, "asm10") == 0) { } else if (strcmp(preset, "asm10") == 0) {
io->is_hpc = 0, io->k = 19, io->w = 19; io->flag = 0, io->k = 19, io->w = 19;
mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = 200; mo->a = 1, mo->b = 9, mo->q = 16, mo->q2 = 41, mo->e = 2, mo->e2 = 1, mo->zdrop = 200;
mo->min_dp_max = 200; mo->min_dp_max = 200;
mo->best_n = 50; mo->best_n = 50;
} else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) { } else if (strcmp(preset, "short") == 0 || strcmp(preset, "sr") == 0) {
io->is_hpc = 0, io->k = 21, io->w = 11; io->flag = 0, io->k = 21, io->w = 11;
mo->flag |= MM_F_SR | MM_F_FRAG_MODE | MM_F_NO_PRINT_2ND | MM_F_2_IO_THREADS; mo->flag |= MM_F_SR | MM_F_FRAG_MODE | MM_F_NO_PRINT_2ND | MM_F_2_IO_THREADS;
mo->pe_ori = 0<<1|1; // FR mo->pe_ori = 0<<1|1; // FR
mo->a = 2, mo->b = 8, mo->q = 12, mo->e = 2, mo->q2 = 24, mo->e2 = 1; mo->a = 2, mo->b = 8, mo->q = 12, mo->e = 2, mo->q2 = 24, mo->e2 = 1;
@@ -104,7 +105,7 @@ int mm_set_opt(const char *preset, mm_idxopt_t *io, mm_mapopt_t *mo)
mo->max_occ = 5000; mo->max_occ = 5000;
mo->mini_batch_size = 50000000; mo->mini_batch_size = 50000000;
} else if (strcmp(preset, "splice") == 0 || strcmp(preset, "cdna") == 0) { } else if (strcmp(preset, "splice") == 0 || strcmp(preset, "cdna") == 0) {
io->is_hpc = 0, io->k = 15, io->w = 5; io->flag = 0, io->k = 15, io->w = 5;
mo->flag |= MM_F_SPLICE | MM_F_SPLICE_FOR | MM_F_SPLICE_REV | MM_F_SPLICE_FLANK; mo->flag |= MM_F_SPLICE | MM_F_SPLICE_FOR | MM_F_SPLICE_REV | MM_F_SPLICE_FLANK;
mo->max_gap = 2000, mo->max_gap_ref = mo->bw = 200000; mo->max_gap = 2000, mo->max_gap_ref = mo->bw = 200000;
mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0; mo->a = 1, mo->b = 2, mo->q = 2, mo->e = 1, mo->q2 = 32, mo->e2 = 0;
@@ -122,8 +123,6 @@ typedef struct {
} mm_match_t; } mm_match_t;
struct mm_tbuf_s { struct mm_tbuf_s {
sdust_buf_t *sdb;
mm128_v mini;
void *km; void *km;
}; };
@@ -132,24 +131,23 @@ mm_tbuf_t *mm_tbuf_init(void)
mm_tbuf_t *b; mm_tbuf_t *b;
b = (mm_tbuf_t*)calloc(1, sizeof(mm_tbuf_t)); b = (mm_tbuf_t*)calloc(1, sizeof(mm_tbuf_t));
if (!(mm_dbg_flag & 1)) b->km = km_init(); if (!(mm_dbg_flag & 1)) b->km = km_init();
b->sdb = sdust_buf_init(b->km);
return b; return b;
} }
void mm_tbuf_destroy(mm_tbuf_t *b) void mm_tbuf_destroy(mm_tbuf_t *b)
{ {
if (b == 0) return; if (b == 0) return;
kfree(b->km, b->mini.a);
sdust_buf_destroy(b->sdb);
km_destroy(b->km); km_destroy(b->km);
free(b); free(b);
} }
static int mm_dust_minier(int n, mm128_t *a, int l_seq, const char *seq, int sdust_thres, sdust_buf_t *sdb) 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; int n_dreg, j, k, u = 0;
const uint64_t *dreg; const uint64_t *dreg;
if (sdust_thres <= 0 || sdb == 0) return n; sdust_buf_t *sdb;
if (sdust_thres <= 0) return n;
sdb = sdust_buf_init(km);
dreg = sdust_core((const uint8_t*)seq, l_seq, sdust_thres, 64, &n_dreg, sdb); dreg = sdust_core((const uint8_t*)seq, l_seq, sdust_thres, 64, &n_dreg, sdb);
for (j = k = 0; j < n; ++j) { // squeeze out minimizers that significantly overlap with LCRs for (j = k = 0; j < n; ++j) { // squeeze out minimizers that significantly overlap with LCRs
int32_t qpos = (uint32_t)a[j].y>>1, span = a[j].x&0xff; int32_t qpos = (uint32_t)a[j].y>>1, span = a[j].x&0xff;
@@ -163,45 +161,49 @@ static int mm_dust_minier(int n, mm128_t *a, int l_seq, const char *seq, int sdu
l += ee - ss; l += ee - ss;
} }
if (l <= span>>1) a[k++] = a[j]; // keep the minimizer if less than half of it falls in masked region if (l <= span>>1) a[k++] = a[j]; // keep the minimizer if less than half of it falls in masked region
} } else a[k++] = a[j];
} }
sdust_buf_destroy(sdb);
return k; // the new size return k; // the new size
} }
static void collect_minimizers(const mm_mapopt_t *opt, const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, mm_tbuf_t *b) static void collect_minimizers(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, mm128_v *mv)
{ {
int i, j, n, sum = 0; int i, j, n, sum = 0;
b->mini.n = 0; mv->n = 0;
for (i = n = 0; i < n_segs; ++i) { for (i = n = 0; i < n_segs; ++i) {
mm_sketch(b->km, seqs[i], qlens[i], mi->w, mi->k, i, mi->is_hpc, &b->mini); mm_sketch(km, seqs[i], qlens[i], mi->w, mi->k, i, mi->flag&MM_I_HPC, mv);
for (j = n; j < b->mini.n; ++j) for (j = n; j < mv->n; ++j)
b->mini.a[j].y += sum << 1; mv->a[j].y += sum << 1;
if (opt->sdust_thres > 0) // mask low-complexity minimizers if (opt->sdust_thres > 0) // mask low-complexity minimizers
b->mini.n = n + mm_dust_minier(b->mini.n - n, b->mini.a + n, qlens[i], seqs[i], opt->sdust_thres, b->sdb); mv->n = n + mm_dust_minier(km, mv->n - n, mv->a + n, qlens[i], seqs[i], opt->sdust_thres);
sum += qlens[i], n = b->mini.n; sum += qlens[i], n = mv->n;
} }
} }
static mm128_t *collect_seed_hits(const mm_mapopt_t *opt, int max_occ, const mm_idx_t *mi, const char *qname, int qlen, int64_t *n_a, int *rep_len, mm_tbuf_t *b) static mm128_t *collect_seed_hits(void *km, const mm_mapopt_t *opt, int max_occ, const mm_idx_t *mi, const char *qname, const mm128_v *mv, int qlen, int64_t *n_a, int *rep_len,
int *n_mini_pos, uint64_t **mini_pos)
{ {
int rep_st = 0, rep_en = 0, i; int rep_st = 0, rep_en = 0, i;
mm_match_t *m; mm_match_t *m;
mm128_t *a; mm128_t *a;
m = (mm_match_t*)kmalloc(b->km, b->mini.n * sizeof(mm_match_t)); *n_mini_pos = 0;
for (i = 0; i < b->mini.n; ++i) { *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; i < mv->n; ++i) {
int t; int t;
mm128_t *p = &b->mini.a[i]; mm128_t *p = &mv->a[i];
m[i].qpos = (uint32_t)p->y; m[i].qpos = (uint32_t)p->y;
m[i].cr = mm_idx_get(mi, p->x>>8, &t); m[i].cr = mm_idx_get(mi, p->x>>8, &t);
m[i].n = t; m[i].n = t;
m[i].seg_id = p->y >> 32; m[i].seg_id = p->y >> 32;
} }
for (i = 0, *n_a = 0; i < b->mini.n; ++i) // find the length of a[] for (i = 0, *n_a = 0; i < mv->n; ++i) // find the length of a[]
if (m[i].n < max_occ) *n_a += m[i].n; if (m[i].n < max_occ) *n_a += m[i].n;
a = (mm128_t*)kmalloc(b->km, *n_a * sizeof(mm128_t)); a = (mm128_t*)kmalloc(km, *n_a * sizeof(mm128_t));
for (i = *rep_len = 0, *n_a = 0; i < b->mini.n; ++i) { for (i = *rep_len = 0, *n_a = 0; i < mv->n; ++i) {
mm128_t *p = &b->mini.a[i]; mm128_t *p = &mv->a[i];
mm_match_t *q = &m[i]; mm_match_t *q = &m[i];
const uint64_t *r = q->cr; const uint64_t *r = q->cr;
int k, q_span = p->x & 0xff, is_tandem = 0; int k, q_span = p->x & 0xff, is_tandem = 0;
@@ -213,8 +215,9 @@ static mm128_t *collect_seed_hits(const mm_mapopt_t *opt, int max_occ, const mm_
} else rep_en = en; } else rep_en = en;
continue; continue;
} }
if (i > 0 && p->x>>8 == b->mini.a[i - 1].x>>8) is_tandem = 1; (*mini_pos)[(*n_mini_pos)++] = (uint64_t)q_span<<32 | q->qpos>>1;
if (i < b->mini.n - 1 && p->x>>8 == b->mini.a[i + 1].x>>8) is_tandem = 1; if (i > 0 && p->x>>8 == mv->a[i - 1].x>>8) is_tandem = 1;
if (i < mv->n - 1 && p->x>>8 == mv->a[i + 1].x>>8) is_tandem = 1;
for (k = 0; k < q->n; ++k) { for (k = 0; k < q->n; ++k) {
int32_t rpos = (uint32_t)r[k] >> 1; int32_t rpos = (uint32_t)r[k] >> 1;
mm128_t *p; mm128_t *p;
@@ -240,7 +243,7 @@ static mm128_t *collect_seed_hits(const mm_mapopt_t *opt, int max_occ, const mm_
} }
} }
*rep_len += rep_en - rep_st; *rep_len += rep_en - rep_st;
kfree(b->km, m); kfree(km, m);
return a; return a;
} }
@@ -258,7 +261,7 @@ static void chain_post(const mm_mapopt_t *opt, int max_chain_gap_ref, const mm_i
static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *km, int qlen, const char *seq, const char *qual, int *n_regs, mm_reg1_t *regs, mm128_t *a) static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *km, int qlen, const char *seq, const char *qual, int *n_regs, mm_reg1_t *regs, mm128_t *a)
{ {
if (!(opt->flag & MM_F_CIGAR)) return regs; if (!(opt->flag & MM_F_CIGAR)) return regs;
regs = mm_align_skeleton(km, opt, mi, qlen, seq, qual, n_regs, regs, a); // this calls mm_filter_regs() regs = mm_align_skeleton(km, opt, mi, qlen, seq, n_regs, regs, a); // this calls mm_filter_regs()
if (!(opt->flag & MM_F_AVA)) { if (!(opt->flag & MM_F_AVA)) {
mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b); mm_set_parent(km, opt->mask_level, *n_regs, regs, opt->a * 2 + opt->b);
mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs); mm_select_sub(km, opt->pri_ratio, mi->k*2, opt->best_n, n_regs, regs);
@@ -269,13 +272,15 @@ static mm_reg1_t *align_regs(const mm_mapopt_t *opt, const mm_idx_t *mi, void *k
void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, const char **quals, int *n_regs, mm_reg1_t **regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname) void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **seqs, const char **quals, int *n_regs, mm_reg1_t **regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
{ {
int i, j, rep_len, qlen_sum, n_regs0; int i, j, rep_len, qlen_sum, n_regs0, n_mini_pos;
int max_chain_gap_qry, max_chain_gap_ref, is_splice = !!(opt->flag & MM_F_SPLICE), is_sr = !!(opt->flag & MM_F_SR); int max_chain_gap_qry, max_chain_gap_ref, is_splice = !!(opt->flag & MM_F_SPLICE), is_sr = !!(opt->flag & MM_F_SR);
uint32_t hash; uint32_t hash;
int64_t n_a; int64_t n_a;
uint64_t *u; uint64_t *u, *mini_pos;
mm128_t *a; mm128_t *a;
mm128_v mv = {0,0,0};
mm_reg1_t *regs0; mm_reg1_t *regs0;
km_stat_t kmst;
for (i = 0, qlen_sum = 0; i < n_segs; ++i) for (i = 0, qlen_sum = 0; i < n_segs; ++i)
qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0; qlen_sum += qlens[i], n_regs[i] = 0, regs[i] = 0;
@@ -286,8 +291,8 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed); hash ^= __ac_Wang_hash(qlen_sum) + __ac_Wang_hash(opt->seed);
hash = __ac_Wang_hash(hash); hash = __ac_Wang_hash(hash);
collect_minimizers(opt, mi, n_segs, qlens, seqs, b); collect_minimizers(b->km, opt, mi, n_segs, qlens, seqs, &mv);
a = collect_seed_hits(opt, opt->mid_occ, mi, qname, qlen_sum, &n_a, &rep_len, b); a = collect_seed_hits(b->km, opt, opt->mid_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
radix_sort_128x(a, a + n_a); radix_sort_128x(a, a + n_a);
if (mm_dbg_flag & MM_DBG_PRINT_SEED) { if (mm_dbg_flag & MM_DBG_PRINT_SEED) {
@@ -327,7 +332,8 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
if (rechain) { // redo chaining with a higher max_occ threshold if (rechain) { // redo chaining with a higher max_occ threshold
kfree(b->km, a); kfree(b->km, a);
kfree(b->km, u); kfree(b->km, u);
a = collect_seed_hits(opt, opt->max_occ, mi, qname, qlen_sum, &n_a, &rep_len, b); kfree(b->km, mini_pos);
a = collect_seed_hits(b->km, opt, opt->max_occ, mi, qname, &mv, qlen_sum, &n_a, &rep_len, &n_mini_pos, &mini_pos);
radix_sort_128x(a, a + n_a); radix_sort_128x(a, a + n_a);
a = mm_chain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->min_cnt, opt->min_chain_score, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km); a = mm_chain_dp(max_chain_gap_ref, max_chain_gap_qry, opt->bw, opt->max_chain_skip, opt->min_cnt, opt->min_chain_score, is_splice, n_segs, n_a, a, &n_regs0, &u, b->km);
} }
@@ -342,6 +348,7 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x)); i == regs0[j].as? 0 : ((int32_t)a[i].y - (int32_t)a[i-1].y) - ((int32_t)a[i].x - (int32_t)a[i-1].x));
chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a); chain_post(opt, max_chain_gap_ref, mi, b->km, qlen_sum, n_segs, qlens, &n_regs0, regs0, a);
if (!is_sr) mm_est_err(mi, qlen_sum, n_regs0, regs0, a, n_mini_pos, mini_pos);
if (n_segs == 1) { // uni-segment if (n_segs == 1) { // uni-segment
regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], quals? quals[0] : 0, &n_regs0, regs0, a); regs0 = align_regs(opt, mi, b->km, qlens[0], seqs[0], quals? quals[0] : 0, &n_regs0, regs0, a);
@@ -361,8 +368,21 @@ void mm_map_frag(const mm_idx_t *mi, int n_segs, const int *qlens, const char **
mm_pair(b->km, max_chain_gap_ref, opt->pe_bonus, opt->a * 2 + opt->b, opt->a, qlens, n_regs, regs); // pairing mm_pair(b->km, max_chain_gap_ref, opt->pe_bonus, opt->a * 2 + opt->b, opt->a, qlens, n_regs, regs); // pairing
} }
kfree(b->km, mv.a);
kfree(b->km, a); kfree(b->km, a);
kfree(b->km, u); kfree(b->km, u);
kfree(b->km, mini_pos);
if (b->km) {
km_stat(b->km, &kmst);
if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
fprintf(stderr, "QM\t%s\t%d\tcap=%ld,nCore=%ld,largest=%ld\n", qname, qlen_sum, kmst.capacity, kmst.n_cores, kmst.largest);
assert(kmst.n_blocks == kmst.n_cores); // otherwise, there is a memory leak
if (kmst.largest > 1U<<28) {
km_destroy(b->km);
b->km = km_init();
}
}
} }
mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname) mm_reg1_t *mm_map(const mm_idx_t *mi, int qlen, const char *seq, int *n_regs, mm_tbuf_t *b, const mm_mapopt_t *opt, const char *qname)
@@ -396,14 +416,13 @@ typedef struct {
static void worker_for(void *_data, long i, int tid) // kt_for() callback static void worker_for(void *_data, long i, int tid) // kt_for() callback
{ {
step_t *s = (step_t*)_data; step_t *s = (step_t*)_data;
int *qlens, j, off = s->seg_off[i], pe_ori = s->p->opt->pe_ori, is_sr = !!(s->p->opt->flag & MM_F_SR); int qlens[MM_MAX_SEG], j, off = s->seg_off[i], pe_ori = s->p->opt->pe_ori, is_sr = !!(s->p->opt->flag & MM_F_SR);
const char **qseqs, **quals = 0; const char *qseqs[MM_MAX_SEG], *quals[MM_MAX_SEG];
mm_tbuf_t *b = s->buf[tid]; mm_tbuf_t *b = s->buf[tid];
assert(s->n_seg[i] <= MM_MAX_SEG);
memset(quals, 0, sizeof(char*) * MM_MAX_SEG);
if (mm_dbg_flag & MM_DBG_PRINT_QNAME) if (mm_dbg_flag & MM_DBG_PRINT_QNAME)
fprintf(stderr, "QR\t%s\t%d\n", s->seq[off].name, tid); fprintf(stderr, "QR\t%s\t%d\t%d\n", s->seq[off].name, tid, s->seq[off].l_seq);
qlens = (int*)kmalloc(b->km, s->n_seg[i] * sizeof(int));
qseqs = (const char**)kmalloc(b->km, s->n_seg[i] * sizeof(const char**));
quals = (const char**)kmalloc(b->km, s->n_seg[i] * sizeof(const char**));
for (j = 0; j < s->n_seg[i]; ++j) { for (j = 0; j < s->n_seg[i]; ++j) {
if (s->n_seg[i] == 2 && ((j == 0 && (pe_ori>>1&1)) || (j == 1 && (pe_ori&1)))) if (s->n_seg[i] == 2 && ((j == 0 && (pe_ori>>1&1)) || (j == 1 && (pe_ori&1))))
mm_revcomp_bseq(&s->seq[off + j]); mm_revcomp_bseq(&s->seq[off + j]);
@@ -429,9 +448,6 @@ static void worker_for(void *_data, long i, int tid) // kt_for() callback
r->rev = !r->rev; r->rev = !r->rev;
} }
} }
kfree(b->km, qlens);
kfree(b->km, qseqs);
kfree(b->km, quals);
} }
static void *worker_pipeline(void *shared, int step, void *in) static void *worker_pipeline(void *shared, int step, void *in)
+21 -13
View File
@@ -24,6 +24,11 @@
#define MM_F_LONG_CIGAR 0x10000 #define MM_F_LONG_CIGAR 0x10000
#define MM_F_INDEPEND_SEG 0x20000 #define MM_F_INDEPEND_SEG 0x20000
#define MM_F_SPLICE_FLANK 0x40000 #define MM_F_SPLICE_FLANK 0x40000
#define MM_F_SOFTCLIP 0x80000
#define MM_I_HPC 0x1
#define MM_I_NO_SEQ 0x2
#define MM_I_NO_NAME 0x4
#define MM_IDX_MAGIC "MMI\2" #define MM_IDX_MAGIC "MMI\2"
@@ -45,7 +50,7 @@ typedef struct {
} mm_idx_seq_t; } mm_idx_seq_t;
typedef struct { typedef struct {
int32_t b, w, k, is_hpc; int32_t b, w, k, flag;
uint32_t n_seq; // number of reference sequences uint32_t n_seq; // number of reference sequences
mm_idx_seq_t *seq; // sequence name, length and offset mm_idx_seq_t *seq; // sequence name, length and offset
uint32_t *S; // 4-bit packed sequence uint32_t *S; // 4-bit packed sequence
@@ -63,23 +68,25 @@ typedef struct {
} mm_extra_t; } mm_extra_t;
typedef struct { typedef struct {
int32_t id; // ID for internal uses (see also parent below) int32_t id; // ID for internal uses (see also parent below)
uint32_t cnt:30, rev:1, seg_split:1; // number of minimizers; if on the reverse strand int32_t cnt; // number of minimizers; if on the reverse strand
uint32_t rid:31, inv:1; // reference index; if this is an alignment from inversion rescue int32_t rid; // reference index; if this is an alignment from inversion rescue
int32_t score; // DP alignment score int32_t score; // DP alignment score
int32_t qs, qe, rs, re; // query start and end; reference start and end int32_t qs, qe, rs, re; // query start and end; reference start and end
int32_t parent, subsc; // parent==id if primary; best alternate mapping score int32_t parent, subsc; // parent==id if primary; best alternate mapping score
int32_t as; // offset in the a[] array (for internal uses only) int32_t as; // offset in the a[] array (for internal uses only)
int32_t mlen, blen; // seeded exact match length; seeded alignment block length int32_t mlen, blen; // seeded exact match length; seeded alignment block length
uint32_t mapq:8, split:2, n_sub:22; // mapQ; split pattern; number of suboptimal mappings int32_t n_sub; // number of suboptimal mappings
uint32_t sam_pri:1, proper_frag:1, iden_flt:1, pe_thru:1, dummy:28; int32_t score0; // initial chaining score (before chain merging/spliting)
uint32_t mapq:8, split:2, rev:1, inv:1, sam_pri:1, proper_frag:1, pe_thru:1, seg_split:1, dummy:16;
uint32_t hash; uint32_t hash;
float div;
mm_extra_t *p; mm_extra_t *p;
} mm_reg1_t; } mm_reg1_t;
// indexing and mapping options // indexing and mapping options
typedef struct { typedef struct {
short k, w, is_hpc, bucket_bits; short k, w, flag, bucket_bits;
int mini_batch_size; int mini_batch_size;
uint64_t batch_size; uint64_t batch_size;
} mm_idxopt_t; } mm_idxopt_t;
@@ -109,6 +116,7 @@ typedef struct {
int end_bonus; int end_bonus;
int min_dp_max; // drop an alignment if the score of the max scoring segment is below this threshold int min_dp_max; // drop an alignment if the score of the max scoring segment is below this threshold
int min_ksw_len; int min_ksw_len;
int anchor_ext_len, anchor_ext_shift;
int pe_ori, pe_bonus; int pe_ori, pe_bonus;
@@ -268,7 +276,7 @@ int mm_map_file_frag(const mm_idx_t *idx, int n_segs, const char **fn, const mm_
// deprecated APIs for backward compatibility // deprecated APIs for backward compatibility
void mm_mapopt_init(mm_mapopt_t *opt); void mm_mapopt_init(mm_mapopt_t *opt);
mm_idx_t *mm_idx_build(const char *fn, int w, int k, int is_hpc, int n_threads); mm_idx_t *mm_idx_build(const char *fn, int w, int k, int flag, int n_threads);
#ifdef __cplusplus #ifdef __cplusplus
} }
+25 -2
View File
@@ -1,4 +1,4 @@
.TH minimap2 1 "6 November 2017" "minimap2-2.4 (r555)" "Bioinformatics tools" .TH minimap2 1 "12 December 2017" "minimap2-2.6 (r623)" "Bioinformatics tools"
.SH NAME .SH NAME
.PP .PP
minimap2 - mapping and alignment between collections of DNA sequences minimap2 - mapping and alignment between collections of DNA sequences
@@ -99,6 +99,14 @@ multiple times to map it against each batch of target sequences.
may be ending with k/K/m/M/g/G. NB: mapping quality is incorrect given a may be ending with k/K/m/M/g/G. NB: mapping quality is incorrect given a
multi-part index. multi-part index.
.TP .TP
.B --idx-no-seq
Don't store target sequences in the index. It saves disk space and memory but
the index generated with this option will not work with
.B -a
or
.BR -c .
When base-level alignment is not requested, this option is automatically applied.
.TP
.BI -d \ FILE .BI -d \ FILE
Save the minimizer index of Save the minimizer index of
.I target.fa .I target.fa
@@ -264,6 +272,18 @@ However, the SIRV control does not honor this trend
on SIRV data, please add on SIRV data, please add
.B --splice-flank=no .B --splice-flank=no
to the command line. to the command line.
.TP
.BI --end-seed-pen \ INT
Drop a terminal anchor if
.IR s <log( g )+ INT ,
where
.I s
is the local alignment score around the anchor and
.I g
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]
.SS Input/output options .SS Input/output options
.TP 10 .TP 10
.B -a .B -a
@@ -302,6 +322,9 @@ is given,
.I short .I short
is assumed. [none] is assumed. [none]
.TP .TP
.B -Y
In SAM output, use soft clipping for supplementary alignments.
.TP
.BI --seed \ INT .BI --seed \ INT
Integer seed for randomizing equally best hits. Minimap2 hashes Integer seed for randomizing equally best hits. Minimap2 hashes
.I INT .I INT
@@ -458,7 +481,7 @@ cb | cb | cb
r | c | l . r | c | l .
Tag Type Description Tag Type Description
_ _
tp A Type of aln: P/primary, S/secondary and I/inversion tp A Type of aln: P/primary, S/secondary and I,i/inversion
cm i Number of minimizers on the chain cm i Number of minimizers on the chain
s1 i Chaining score s1 i Chaining score
s2 i Chaining score of the best secondary chain s2 i Chaining score of the best secondary chain
+2 -1
View File
@@ -161,7 +161,8 @@ for (var tid in tr) {
if (anno[t[0]] == null) anno[t[0]] = []; if (anno[t[0]] == null) anno[t[0]] = [];
var s = t[4]; var s = t[4];
for (var i = 0; i < s.length - 1; ++i) { for (var i = 0; i < s.length - 1; ++i) {
if (s[i][1] >= s[i+1][0]) throw Error("ERROR: wrong annotation!"); if (s[i][1] >= s[i+1][0])
warn("WARNING: incorrect annotation for transcript "+tid+" ("+s[i][1]+" >= "+s[i+1][0]+")")
anno[t[0]].push([s[i][1], s[i+1][0]]); anno[t[0]].push([s[i][1], s[i+1][0]]);
} }
} }
+64 -39
View File
@@ -36,20 +36,21 @@ var getopt = function(args, ostr) {
return optopt; return optopt;
} }
var c, maf_out = false, line_len = 80; var c, line_len = 80, fmt = "aln";
while ((c = getopt(arguments, "ml:")) != null) { while ((c = getopt(arguments, "f:l:")) != null) {
if (c == 'm') maf_out = true; if (c == 'f') {
else if (c == 'l') line_len = parseInt(getopt.arg); // TODO: not implemented yet fmt = getopt.arg;
if (fmt != "aln" && fmt != "lastz-cigar" && fmt != "maf")
throw Error("format must be one of aln, lastz-cigar and maf");
} else if (c == 'l') line_len = parseInt(getopt.arg);
} }
if (line_len == 0) line_len = 0x7fffffff; if (line_len == 0) line_len = 0x7fffffff;
if (getopt.ind == arguments.length) { if (getopt.ind == arguments.length) {
print("Usage: k8 paf2aln.js [options] <with-cs.paf>"); print("Usage: k8 paf2aln.js [options] <in.paf>");
print("Options:"); print("Options:");
print(" -m MAF output (BLAST-like output by default)"); print(" -f STR output format: aln (BLAST-like), maf or lastz-cigar [aln]");
print(" -l INT line length in BLAST-like output [80]"); print(" -l INT line length in BLAST-like output [80]");
print("");
print("Note: this script only works when minimap2 is run with option '-S'");
exit(1); exit(1);
} }
@@ -66,7 +67,7 @@ function padding_str(x, len, right)
function update_aln(s_ref, s_qry, s_mid, type, seq, slen) function update_aln(s_ref, s_qry, s_mid, type, seq, slen)
{ {
var l = type == '*'? 1 : seq.length; var l = type == '*'? 1 : seq.length;
if (type == '=') { if (type == '=' || type == ':') {
s_ref.set(seq); s_ref.set(seq);
s_qry.set(seq); s_qry.set(seq);
s_mid.set(Array(l+1).join("|")); s_mid.set(Array(l+1).join("|"));
@@ -96,49 +97,73 @@ function print_aln(rs, qs, strand, slen, elen, s_ref, s_qry, s_mid)
var st, en; var st, en;
if (strand == '+') st = qs + slen[1] + 1, en = qs + elen[1]; if (strand == '+') st = qs + slen[1] + 1, en = qs + elen[1];
else st = qs - slen[1], en = qs - elen[1] + 1; else st = qs - slen[1], en = qs - elen[1] + 1;
print(["Qry" + strand + ":", padding_str(st, 10, false), s_qry.toString(), padding_str(en , 10, true)].join(" ")); print(["Qry" + strand + ":", padding_str(st, 10, false), s_qry.toString(), padding_str(en, 10, true)].join(" "));
} }
var s_ref = new Bytes(), s_qry = new Bytes(), s_mid = new Bytes(); var s_ref = new Bytes(), s_qry = new Bytes(), s_mid = new Bytes(); // these are used to show padded alignment
var re = /([=\-\+\*])([A-Za-z]+)/g; var re_cs = /([:=\-\+\*])(\d+|[A-Za-z]+)/g;
var re_cg = /(\d+)([MIDNSH])/g;
var buf = new Bytes(); var buf = new Bytes();
var file = new File(arguments[getopt.ind]); var file = arguments[getopt.ind] == "-"? new File() : new File(arguments[getopt.ind]);
if (maf_out) print("##maf version=1\n"); var lineno = 0;
if (fmt == "maf") print("##maf version=1\n");
while (file.readline(buf) >= 0) { while (file.readline(buf) >= 0) {
var m, line = buf.toString(); var m, line = buf.toString();
var t = line.split("\t", 12); var t = line.split("\t", 12);
if ((m = /\tcs:Z:(\S+)/.exec(line)) == null) continue; ++lineno;
var cs = m[1];
s_ref.length = s_qry.length = s_mid.length = 0; s_ref.length = s_qry.length = s_mid.length = 0;
var slen = [0, 0], elen = [0, 0]; var slen = [0, 0], elen = [0, 0];
if (maf_out) { if (fmt == "lastz-cigar") { // LASTZ-cigar output
while ((m = re.exec(cs)) != null) var cg = (m = /\tcg:Z:(\S+)/.exec(line)) != null? m[1] : null;
update_aln(s_ref, s_qry, s_mid, m[1], m[2], elen); if (cg == null) {
if (maf_out) { warn("WARNING: converting to LASTZ-cigar format requires the 'cg' tag, which is absent on line " + lineno);
var score = (m = /\tAS:i:(\d+)/.exec(line)) != null? parseInt(m[1]) : 0; continue;
var len = t[0].length > t[5].length? t[0].length : t[5].length;
print("a " + score);
print(["s", padding_str(t[5], len, true), padding_str(t[7], 10, false), padding_str(parseInt(t[8]) - parseInt(t[7]), 10, false),
"+", padding_str(t[6], 10, false), s_ref.toString()].join(" "));
var qs, qe, ql = parseInt(t[1]);
if (t[4] == '+') {
qs = parseInt(t[2]);
qe = parseInt(t[3]);
} else {
qs = ql - parseInt(t[3]);
qe = ql - parseInt(t[2]);
}
print(["s", padding_str(t[0], len, true), padding_str(qs, 10, false), padding_str(qe - qs, 10, false),
t[4], padding_str(ql, 10, false), s_qry.toString()].join(" "));
print("");
} }
} else { var score = (m = /\tAS:i:(\d+)/.exec(line)) != null? m[1] : 0;
line = line.replace(/\tc[sg]:Z:\S+/g, ""); var out = ['cigar:', t[0], t[2], t[3], t[4], t[5], t[7], t[8], '+', score];
while ((m = re_cg.exec(cg)) != null)
out.push(m[2], m[1]);
print(out.join(" "));
} else if (fmt == "maf") { // MAF output
var cs = (m = /\tcs:Z:(\S+)/.exec(line)) != null? m[1] : null;
if (cs == null) {
warn("WARNING: converting to MAF requires the 'cs' tag, which is absent on line " + lineno);
continue;
}
while ((m = re_cs.exec(cs)) != null) {
if (m[1] == ':')
throw Error("converting to MAF only works with 'minimap2 --cs=long'");
update_aln(s_ref, s_qry, s_mid, m[1], m[2], elen);
}
var score = (m = /\tAS:i:(\d+)/.exec(line)) != null? parseInt(m[1]) : 0;
var len = t[0].length > t[5].length? t[0].length : t[5].length;
print("a " + score);
print(["s", padding_str(t[5], len, true), padding_str(t[7], 10, false), padding_str(parseInt(t[8]) - parseInt(t[7]), 10, false),
"+", padding_str(t[6], 10, false), s_ref.toString()].join(" "));
var qs, qe, ql = parseInt(t[1]);
if (t[4] == '+') {
qs = parseInt(t[2]);
qe = parseInt(t[3]);
} else {
qs = ql - parseInt(t[3]);
qe = ql - parseInt(t[2]);
}
print(["s", padding_str(t[0], len, true), padding_str(qs, 10, false), padding_str(qe - qs, 10, false),
t[4], padding_str(ql, 10, false), s_qry.toString()].join(" "));
print("");
} else { // BLAST-like output
var cs = (m = /\tcs:Z:(\S+)/.exec(line)) != null? m[1] : null;
if (cs == null) {
warn("WARNING: converting to BLAST-like alignment requires the 'cs' tag, which is absent on line " + lineno);
continue;
}
line = line.replace(/\tc[sg]:Z:\S+/g, ""); // get rid of cs or cg tags
print('>' + line); print('>' + line);
var rs = parseInt(t[7]), qs = t[4] == '+'? parseInt(t[2]) : parseInt(t[3]); var rs = parseInt(t[7]), qs = t[4] == '+'? parseInt(t[2]) : parseInt(t[3]);
var n_blocks = 0; var n_blocks = 0;
while ((m = re.exec(cs)) != null) { while ((m = re_cs.exec(cs)) != null) {
if (m[1] == ':') m[2] = Array(parseInt(m[2]) + 1).join("=");
var start = 0, rest = m[1] == '*'? 1 : m[2].length; var start = 0, rest = m[1] == '*'? 1 : m[2].length;
while (rest > 0) { while (rest > 0) {
var l_proc; var l_proc;
+188
View File
@@ -0,0 +1,188 @@
var getopt = function(args, ostr) {
var oli; // option letter list index
if (typeof(getopt.place) == 'undefined')
getopt.ind = 0, getopt.arg = null, getopt.place = -1;
if (getopt.place == -1) { // update scanning pointer
if (getopt.ind >= args.length || args[getopt.ind].charAt(getopt.place = 0) != '-') {
getopt.place = -1;
return null;
}
if (getopt.place + 1 < args[getopt.ind].length && args[getopt.ind].charAt(++getopt.place) == '-') { // found "--"
++getopt.ind;
getopt.place = -1;
return null;
}
}
var optopt = args[getopt.ind].charAt(getopt.place++); // character checked for validity
if (optopt == ':' || (oli = ostr.indexOf(optopt)) < 0) {
if (optopt == '-') return null; // if the user didn't specify '-' as an option, assume it means null.
if (getopt.place < 0) ++getopt.ind;
return '?';
}
if (oli+1 >= ostr.length || ostr.charAt(++oli) != ':') { // don't need argument
getopt.arg = null;
if (getopt.place < 0 || getopt.place >= args[getopt.ind].length) ++getopt.ind, getopt.place = -1;
} else { // need an argument
if (getopt.place >= 0 && getopt.place < args[getopt.ind].length)
getopt.arg = args[getopt.ind].substr(getopt.place);
else if (args.length <= ++getopt.ind) { // no arg
getopt.place = -1;
if (ostr.length > 0 && ostr.charAt(0) == ':') return ':';
return '?';
} else getopt.arg = args[getopt.ind]; // white space
getopt.place = -1;
++getopt.ind;
}
return optopt;
}
var re_cs = /([:=*+-])(\d+|[A-Za-z]+)/g;
var c, min_cov_len = 10000, min_var_len = 50000, gap_thres = 50, min_mapq = 5;
while ((c = getopt(arguments, "l:L:g:q:")) != null) {
if (c == 'l') min_cov_len = parseInt(getopt.arg);
else if (c == 'L') min_var_len = parseInt(optarg.arg);
else if (c == 'g') gap_thres = parseInt(optarg.arg);
else if (c == 'q') min_mapq = parseInt(optarg.arg);
}
if (arguments.length == getopt.ind) {
print("Usage: k8 paf2diff.js [options] <with-cs.paf>");
print("Options:");
print(" -l INT min alignment length to compute coverage ["+min_cov_len+"]");
print(" -L INT min alignment length to call variants ["+min_var_len+"]");
print(" -q INT min mapping quality ["+min_mapq+"]");
print(" -g INT short/long gap threshold (for statistics only) ["+gap_thres+"]");
exit(1);
}
var file = new File(arguments[getopt.ind]);
var buf = new Bytes();
var tot_len = 0, n_sub = [0, 0, 0], n_ins = [0, 0, 0, 0], n_del = [0, 0, 0, 0];
function count_var(o)
{
if (o[3] > 1) return;
if (o[5] == '-' && o[6] == '-') return;
if (o[5] == '-') { // insertion
var l = o[6].length;
if (l == 1) ++n_ins[0];
else if (l == 2) ++n_ins[1];
else if (l < gap_thres) ++n_ins[2];
else ++n_ins[3];
} else if (o[6] == '-') { // deletion
var l = o[5].length;
if (l == 1) ++n_del[0];
else if (l == 2) ++n_del[1];
else if (l < gap_thres) ++n_del[2];
else ++n_del[3];
} else {
++n_sub[0];
var s = o[5] + o[6];
if (s == 'ag' || s == 'ga' || s == 'ct' || s == 'tc')
++n_sub[1];
else ++n_sub[2];
}
}
var a = [], out = [];
var c1_ctg = null, c1_start = 0, c1_end = 0, c1_counted = false, c1_len = 0;
while (file.readline(buf) >= 0) {
var line = buf.toString();
if (!/\ts2:i:/.test(line)) continue; // skip secondary alignments
var m, t = line.split("\t", 12);
for (var i = 6; i <= 11; ++i)
t[i] = parseInt(t[i]);
if (t[10] < min_cov_len || t[11] < min_mapq) continue;
var ctg = t[5], x = t[7], end = t[8];
// compute regions covered by 1 contig
if (ctg != c1_ctg || x >= c1_end) {
if (c1_counted && c1_end > c1_start) {
c1_len += c1_end - c1_start;
print('R', c1_ctg, c1_start, c1_end);
}
c1_ctg = ctg, c1_start = x, c1_end = end;
c1_counted = (t[10] >= min_var_len);
} else if (end > c1_end) { // overlap
if (c1_counted && x > c1_start) {
c1_len += x - c1_start;
print('R', c1_ctg, c1_start, x);
}
c1_start = c1_end, c1_end = end;
c1_counted = (t[10] >= min_var_len);
} else { // contained
if (c1_counted && x > c1_start) {
c1_len += x - c1_start;
print('R', c1_ctg, c1_start, x);
}
c1_start = end;
}
// output variants ahead of this alignment
while (out.length) {
if (out[0][0] != ctg || out[0][2] <= x) {
count_var(out[0]);
print('V', out[0].join("\t"));
out.shift();
} else break;
}
// update coverage
for (var i = 0; i < out.length; ++i)
if (out[i][1] >= x && out[i][2] <= end)
++out[i][3];
// drop alignments that don't overlap with the current one
var k = 0;
for (var i = 0; i < a.length; ++i)
if (a[0][0] == ctg && a[0][2] > x)
a[k++] = a[i];
a.length = k;
// core loop
if (t[10] >= min_var_len) {
if ((m = /\tcs:Z:(\S+)/.exec(line)) == null) continue; // no cs tag
var cs = m[1];
var blen = 0, n_diff = 0;
tot_len += t[10];
while ((m = re_cs.exec(cs)) != null) {
var cov = 1;
if (m[1] == '*' || m[1] == '+' || m[1] == '-')
for (var i = 0; i < a.length; ++i)
if (a[0][2] > x) ++cov;
if (m[1] == '=' || m[1] == ':') {
var l = m[1] == '='? m[2].length : parseInt(m[2]);
x += l, blen += l;
} else if (m[1] == '*') {
out.push([t[5], x, x+1, cov, t[11], m[2].charAt(0), m[2].charAt(1)]);
++x, ++blen, ++n_diff;
} else if (m[1] == '+') {
out.push([t[5], x, x, cov, t[11], '-', m[2]]);
++blen, ++n_diff;
} else if (m[1] == '-') {
out.push([t[5], x, x + m[2].length, cov, t[11], m[2], '-']);
x += m[2].length, ++blen, ++n_diff;
}
}
}
a.push([t[5], t[7], t[8]]);
}
if (c1_counted && c1_end > c1_start) {
c1_len += c1_end - c1_start;
print('R', c1_ctg, c1_start, c1_end);
}
while (out.length) {
count_var(out[0]);
print('V', out[0].join("\t"));
out.shift();
}
//warn(tot_len + " alignment columns considered in calling");
warn(c1_len + " reference bases covered by exactly one contig");
warn(n_sub[0] + " substitutions; ts/tv = " + (n_sub[1]/n_sub[2]).toFixed(3));
warn(n_del[0] + " 1bp deletions");
warn(n_ins[0] + " 1bp insertions");
warn(n_del[1] + " 2bp deletions");
warn(n_ins[1] + " 2bp insertions");
warn(n_del[2] + " [3,"+gap_thres+") deletions");
warn(n_ins[2] + " [3,"+gap_thres+") insertions");
warn(n_del[3] + " >="+gap_thres+" deletions");
warn(n_ins[3] + " >="+gap_thres+" insertions");
buf.destroy();
file.close();
+127
View File
@@ -0,0 +1,127 @@
var getopt = function(args, ostr) {
var oli; // option letter list index
if (typeof(getopt.place) == 'undefined')
getopt.ind = 0, getopt.arg = null, getopt.place = -1;
if (getopt.place == -1) { // update scanning pointer
if (getopt.ind >= args.length || args[getopt.ind].charAt(getopt.place = 0) != '-') {
getopt.place = -1;
return null;
}
if (getopt.place + 1 < args[getopt.ind].length && args[getopt.ind].charAt(++getopt.place) == '-') { // found "--"
++getopt.ind;
getopt.place = -1;
return null;
}
}
var optopt = args[getopt.ind].charAt(getopt.place++); // character checked for validity
if (optopt == ':' || (oli = ostr.indexOf(optopt)) < 0) {
if (optopt == '-') return null; // if the user didn't specify '-' as an option, assume it means null.
if (getopt.place < 0) ++getopt.ind;
return '?';
}
if (oli+1 >= ostr.length || ostr.charAt(++oli) != ':') { // don't need argument
getopt.arg = null;
if (getopt.place < 0 || getopt.place >= args[getopt.ind].length) ++getopt.ind, getopt.place = -1;
} else { // need an argument
if (getopt.place >= 0 && getopt.place < args[getopt.ind].length)
getopt.arg = args[getopt.ind].substr(getopt.place);
else if (args.length <= ++getopt.ind) { // no arg
getopt.place = -1;
if (ostr.length > 0 && ostr.charAt(0) == ':') return ':';
return '?';
} else getopt.arg = args[getopt.ind]; // white space
getopt.place = -1;
++getopt.ind;
}
return optopt;
}
var colors = ["0,128,255", "255,0,0", "0,192,0"];
function print_lines(a, fmt) {
if (a.length == 0) return;
if (fmt == "bed") {
var n_pri = 0;
for (var i = 0; i < a.length; ++i)
if (a[i][8] == 0) ++n_pri;
if (n_pri > 1) {
for (var i = 0; i < a.length; ++i)
if (a[i][8] == 0) a[i][8] = 1;
} else if (n_pri == 0) {
warn("Warning: " + a[0][3] + " doesn't have a primary alignment");
}
for (var i = 0; i < a.length; ++i) {
a[i][8] = colors[a[i][8]];
print(a[i].join("\t"));
}
}
a.length = 0;
}
function main(args) {
var re = /(\d+)([MIDNSH])/g;
var c, fmt = "bed";
while ((c = getopt(args, "f:")) != null) {
if (c == 'f') fmt = getopt.arg;
}
if (getopt.ind == args.length) {
warn("Usage: k8 splice2bed.js <in.paf>");
exit(1);
}
var file = new File(args[getopt.ind]);
var buf = new Bytes();
var a = [];
while (file.readline(buf) >= 0) {
var line = buf.toString();
if (line.charAt(0) == '@') continue; // skip SAM header lines
var t = line.split("\t");
var is_pri = false, cigar = null, a1;
if (a.length && a[0][3] != t[0]) {
print_lines(a, fmt);
a = [];
}
if (t.length >= 12 && (t[4] == '+' || t[4] == '-')) {
for (var i = 12; i < t.length; ++i) {
if (t[i].substr(0, 5) == 'cg:Z:') {
cigar = t[i].substr(5);
} else if (t[i].substr(0, 5) == 's2:i:') {
is_pri = true;
}
}
a1 = [t[5], t[7], t[8], t[0], Math.floor(t[9]/t[10]*1000), t[4]];
} else if (t.length >= 10) {
var flag = parseInt(t[1]);
if ((flag&4) || a[2] == '*') continue;
cigar = t[5];
is_pri = (flag&0x100)? false : true;
a1 = [t[2], parseInt(t[3])-1, null, t[0], 1000, (flag&16)? '-' : '+'];
} else {
throw Error("unrecognized input format");
}
if (cigar == null) throw Error("missing CIGAR");
var m, x0 = 0, x = 0, bs = [], bl = [];
while ((m = re.exec(cigar)) != null) {
if (m[2] == 'M' || m[2] == 'D') {
x += parseInt(m[1]);
} else if (m[2] == 'N') {
bs.push(x0);
bl.push(x - x0);
x += parseInt(m[1]);
x0 = x;
}
}
bs.push(x0);
bl.push(x - x0);
// write the BED12 line
if (a1[2] == null) a1[2] = a1[1] + x;
a1.push(a1[1], a1[2]); // thick start/end is the same as start/end
a1.push(is_pri? 0 : 2, bs.length, bl.join(",")+",", bs.join(",")+",");
a.push(a1);
}
print_lines(a, fmt);
buf.destroy();
file.close();
}
main(arguments);
+3 -1
View File
@@ -64,7 +64,7 @@ const uint64_t *mm_idx_get(const mm_idx_t *mi, uint64_t minier, int *n);
int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq); int mm_idx_getseq(const mm_idx_t *mi, uint32_t rid, uint32_t st, uint32_t en, uint8_t *seq);
int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f); int32_t mm_idx_cal_max_occ(const mm_idx_t *mi, float f);
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); 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, const char *qual, int *n_regs_, mm_reg1_t *regs, mm128_t *a); mm_reg1_t *mm_align_skeleton(void *km, const mm_mapopt_t *opt, const mm_idx_t *mi, int qlen, const char *qstr, int *n_regs_, mm_reg1_t *regs, mm128_t *a);
mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a); mm_reg1_t *mm_gen_regs(void *km, uint32_t hash, int qlen, int n_u, uint64_t *u, mm128_t *a);
void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a); void mm_split_reg(mm_reg1_t *r, mm_reg1_t *r2, int n, int qlen, mm128_t *a);
@@ -79,6 +79,8 @@ void mm_join_long(void *km, const mm_mapopt_t *opt, int qlen, int *n_regs, mm_re
void mm_hit_sort_by_dp(void *km, int *n_regs, mm_reg1_t *r); void mm_hit_sort_by_dp(void *km, int *n_regs, mm_reg1_t *r);
void mm_set_mapq(int n_regs, mm_reg1_t *regs, int min_chain_sc, int match_sc, int rep_len, int is_sr); void mm_set_mapq(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);
mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int n_regs0, const mm_reg1_t *regs0, int *n_regs, mm_reg1_t **regs, const mm128_t *a); mm_seg_t *mm_seg_gen(void *km, uint32_t hash, int n_segs, const int *qlens, int n_regs0, const mm_reg1_t *regs0, int *n_regs, mm_reg1_t **regs, const mm128_t *a);
void mm_seg_free(void *km, int n_segs, mm_seg_t *segs); 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); 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);
+3 -2
View File
@@ -5,7 +5,7 @@ cdef extern from "minimap.h":
# Options # Options
# #
ctypedef struct mm_idxopt_t: ctypedef struct mm_idxopt_t:
short k, w, is_hpc, bucket_bits short k, w, flag, bucket_bits
int mini_batch_size int mini_batch_size
uint64_t batch_size uint64_t batch_size
@@ -30,6 +30,7 @@ cdef extern from "minimap.h":
int end_bonus int end_bonus
int min_dp_max int min_dp_max
int min_ksw_len int min_ksw_len
int anchor_ext_len, anchor_ext_shift
int pe_ori, pe_bonus int pe_ori, pe_bonus
float mid_occ_frac float mid_occ_frac
int32_t mid_occ int32_t mid_occ
@@ -51,7 +52,7 @@ cdef extern from "minimap.h":
pass pass
ctypedef struct mm_idx_t: ctypedef struct mm_idx_t:
int32_t b, w, k, is_hpc int32_t b, w, k, flag
uint32_t n_seq uint32_t n_seq
mm_idx_seq_t *seq mm_idx_seq_t *seq
uint32_t *S uint32_t *S
+7 -4
View File
@@ -13,7 +13,8 @@ cdef class Alignment:
cdef _ctg, _cigar # these are python objects cdef _ctg, _cigar # these are python objects
def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand): def __cinit__(self, ctg, cl, cs, ce, strand, qs, qe, mapq, cigar, is_primary, mlen, blen, NM, trans_strand):
self._ctg, self._ctg_len, self._r_st, self._r_en = str(ctg), cl, cs, ce 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 self._strand, self._q_st, self._q_en = strand, qs, qe
self._NM, self._mlen, self._blen = NM, mlen, blen self._NM, self._mlen, self._blen = NM, mlen, blen
self._mapq = mapq self._mapq = mapq
@@ -34,7 +35,7 @@ cdef class Alignment:
def r_en(self): return self._r_en def r_en(self): return self._r_en
@property @property
def strand(self): return self.strand def strand(self): return self._strand
@property @property
def trans_strand(self): return self._trans_strand def trans_strand(self): return self._trans_strand
@@ -150,9 +151,11 @@ def fastx_read(fn):
ks = cmappy.mm_fastx_open(str.encode(fn)) ks = cmappy.mm_fastx_open(str.encode(fn))
if ks is NULL: return None if ks is NULL: return None
while cmappy.kseq_read(ks) >= 0: while cmappy.kseq_read(ks) >= 0:
if ks.qual.l > 0: qual = str(ks.qual.s) if ks.qual.l > 0: qual = ks.qual.s if isinstance(ks.qual.s, str) else ks.qual.s.decode()
else: qual = None else: qual = None
yield str(ks.name.s), str(ks.seq.s), qual name = ks.name.s if isinstance(ks.name.s, str) else ks.name.s.decode()
seq = ks.seq.s if isinstance(ks.seq.s, str) else ks.seq.s.decode()
yield name, seq, qual
cmappy.mm_fastx_close(ks) cmappy.mm_fastx_close(ks)
def verbose(v=None): def verbose(v=None):
+1
View File
@@ -56,6 +56,7 @@ sdust_buf_t *sdust_buf_init(void *km)
buf = (sdust_buf_t*)kcalloc(km, 1, sizeof(sdust_buf_t)); buf = (sdust_buf_t*)kcalloc(km, 1, sizeof(sdust_buf_t));
buf->km = km; buf->km = km;
buf->w = kdq_init(int, buf->km); buf->w = kdq_init(int, buf->km);
kdq_resize(int, buf->w, 8);
return buf; return buf;
} }
+2 -2
View File
@@ -23,7 +23,7 @@ def readme():
setup( setup(
name = 'mappy', name = 'mappy',
version = '2.4', version = '2.6',
url = 'https://github.com/lh3/minimap2', url = 'https://github.com/lh3/minimap2',
description = 'Minimap2 python binding', description = 'Minimap2 python binding',
long_description = readme(), long_description = readme(),
@@ -35,7 +35,7 @@ setup(
ext_modules = [Extension('mappy', ext_modules = [Extension('mappy',
sources = [module_src, 'align.c', 'bseq.c', 'chain.c', 'format.c', 'hit.c', 'index.c', 'pe.c', sources = [module_src, 'align.c', 'bseq.c', 'chain.c', 'format.c', 'hit.c', 'index.c', 'pe.c',
'ksw2_extd2_sse.c', 'ksw2_exts2_sse.c', 'ksw2_extz2_sse.c', 'ksw2_ll_sse.c', 'ksw2_extd2_sse.c', 'ksw2_exts2_sse.c', 'ksw2_extz2_sse.c', 'ksw2_ll_sse.c',
'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c'], 'kalloc.c', 'kthread.c', 'map.c', 'misc.c', 'sdust.c', 'sketch.c', 'esterr.c'],
depends = ['minimap.h', 'bseq.h', 'kalloc.h', 'kdq.h', 'khash.h', 'kseq.h', 'ksort.h', depends = ['minimap.h', 'bseq.h', 'kalloc.h', 'kdq.h', 'khash.h', 'kseq.h', 'ksort.h',
'ksw2.h', 'kthread.h', 'kvec.h', 'mmpriv.h', 'sdust.h', 'ksw2.h', 'kthread.h', 'kvec.h', 'mmpriv.h', 'sdust.h',
'python/cmappy.h', 'python/cmappy.pxd'], 'python/cmappy.h', 'python/cmappy.pxd'],
+5 -5
View File
@@ -115,12 +115,12 @@ void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, i
buf[buf_pos] = info; // need to do this here as appropriate buf_pos and buf[buf_pos] are needed below buf[buf_pos] = info; // need to do this here as appropriate buf_pos and buf[buf_pos] are needed below
if (l == w + k - 1) { // special case for the first window - because identical k-mers are not stored yet if (l == w + k - 1) { // special case for the first window - because identical k-mers are not stored yet
for (j = buf_pos + 1; j < w; ++j) for (j = buf_pos + 1; j < w; ++j)
if (min.x == buf[j].x && buf[j].y != min.y) kv_push(mm128_t, km, *p, buf[j]); if (min.x == buf[j].x && buf[j].y != min.y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
for (j = 0; j < buf_pos; ++j) for (j = 0; j < buf_pos; ++j)
if (min.x == buf[j].x && buf[j].y != min.y) kv_push(mm128_t, km, *p, buf[j]); if (min.x == buf[j].x && buf[j].y != min.y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
} }
if (info.x <= min.x) { // a new minimum; then write the old min if (info.x <= min.x) { // a new minimum; then write the old min
if (l >= w + k) kv_push(mm128_t, km, *p, min); if (l >= w + k && min.y != UINT64_MAX) kv_push(mm128_t, km, *p, min);
min = info, min_pos = buf_pos; min = info, min_pos = buf_pos;
} else if (buf_pos == min_pos) { // old min has moved outside the window } else if (buf_pos == min_pos) { // old min has moved outside the window
if (l >= w + k - 1) kv_push(mm128_t, km, *p, min); if (l >= w + k - 1) kv_push(mm128_t, km, *p, min);
@@ -130,9 +130,9 @@ void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, i
if (min.x >= buf[j].x) min = buf[j], min_pos = j; if (min.x >= buf[j].x) min = buf[j], min_pos = j;
if (l >= w + k - 1) { // write identical k-mers if (l >= w + k - 1) { // write identical k-mers
for (j = buf_pos + 1; j < w; ++j) // these two loops make sure the output is sorted for (j = buf_pos + 1; j < w; ++j) // these two loops make sure the output is sorted
if (min.x == buf[j].x && min.y != buf[j].y) kv_push(mm128_t, km, *p, buf[j]); if (min.x == buf[j].x && min.y != buf[j].y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
for (j = 0; j <= buf_pos; ++j) for (j = 0; j <= buf_pos; ++j)
if (min.x == buf[j].x && min.y != buf[j].y) kv_push(mm128_t, km, *p, buf[j]); if (min.x == buf[j].x && min.y != buf[j].y && buf[j].y != UINT64_MAX) kv_push(mm128_t, km, *p, buf[j]);
} }
} }
if (++buf_pos == w) buf_pos = 0; if (++buf_pos == w) buf_pos = 0;