From 5cb61f8ee67335e65ba7facf1f30715e50e3ce7e Mon Sep 17 00:00:00 2001 From: Heng Li Date: Thu, 6 Jun 2019 10:47:33 -0400 Subject: [PATCH 01/14] added FAQ --- FAQ.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 7 ++++--- 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 FAQ.md diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..94a1bbc --- /dev/null +++ b/FAQ.md @@ -0,0 +1,46 @@ +#### 1. Alignment different with option `-a` or `-c`? + +Without `-a`, `-c` or `--cs`, minimap2 only finds *approximate* mapping +locations without detailed base alignment. In particular, the start and end +positions of the alignment are impricise. With one of those options, minimap2 +will perform base alignment, which is generally more accurate but is much +slower. + +#### 2. How to map Illumina short reads to noisy long reads? + +No good solutions. The better approach is to assemble short reads into contigs +and then map noisy reads to contigs. + +#### 3. The output SAM doesn't have a header. + +By default, minimap2 indexes 4 billion reference bases (4Gb) in a batch and map +all reads against each reference batch. Given a reference longer than 4Gb, +minimap2 is unable to see all the sequences and thus can't produce a correct +SAM header. In this case, minimap2 doesn't output any SAM header. There are two +solutions to this issue. First, you may increase option `-I` to, for example, +`-I8g` to index more reference bases in a batch. This is preferred if your +machine has enough memory. Second, if your machines doesn't have enough memory +to hold the reference index, you can use the `--split-prefix` option in a +command line like: +```sh +minimap2 -ax map-ont --split-prefix=tmp ref.fa reads.fq +``` +This second approach uses less memory, but it is slower and requires temporary +disk space. + +#### 4. The output SAM is malformatted. + +This typically happens when you use nohup to wrap a minimap2 command line. +Nohup is discouraged as it breaks piping. If you have to use nohup, please +specify an output file with option `-o`. + +#### 5. How to output one alignment per read? + +You can use `--secondary=no` to suppress secondary alignments (aka multiple +mappings), but you can't suppress supplementary alignment (aka split or +chimeric alignment) this way. You can use samtools to filter out these +alignments: +```sh +minimap2 -ax map-out ref.fa reads.fq | samtools view -F0x900 +``` +However, this is discouraged as supplementary alignment is informative. diff --git a/README.md b/README.md index 5e39daf..addeb2c 100644 --- a/README.md +++ b/README.md @@ -315,9 +315,10 @@ highlighted in bold. The description may help to tune minimap2 parameters. ### Getting help Manpage [minimap2.1][manpage] provides detailed description of minimap2 -command line options and optional tags. If you encounter bugs or have further -questions or requests, you can raise an issue at the [issue page][issue]. -There is not a specific mailing list for the time being. +command line options and optional tags. The [FAQ](FAQ.md) page answers several +frequently asked questions. If you encounter bugs or have further questions or +requests, you can raise an issue at the [issue page][issue]. There is not a +specific mailing list for the time being. ### Citing minimap2 From 03dc8d5d9777a01565bd660cab3d4d4480003843 Mon Sep 17 00:00:00 2001 From: Heng Li Date: Fri, 7 Jun 2019 09:11:11 -0400 Subject: [PATCH 02/14] test if index is built for #413 --- python/mappy.pyx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/python/mappy.pyx b/python/mappy.pyx index f036450..f9b9ffe 100644 --- a/python/mappy.pyx +++ b/python/mappy.pyx @@ -113,6 +113,7 @@ cdef class Aligner: cdef cmappy.mm_mapopt_t map_opt def __cinit__(self, fn_idx_in=None, preset=None, k=None, w=None, min_cnt=None, min_chain_score=None, min_dp_score=None, bw=None, best_n=None, n_threads=3, fn_idx_out=None, max_frag_len=None, extra_flags=None, seq=None, scoring=None): + self._idx = NULL cmappy.mm_set_opt(NULL, &self.idx_opt, &self.map_opt) # set the default options if preset is not None: cmappy.mm_set_opt(str.encode(preset), &self.idx_opt, &self.map_opt) # apply preset @@ -170,6 +171,7 @@ cdef class Aligner: cdef void *km cdef cmappy.mm_mapopt_t map_opt + if self._idx == NULL: return map_opt = self.map_opt if max_frag_len is not None: map_opt.max_frag_len = max_frag_len if extra_flags is not None: map_opt.flag |= extra_flags @@ -206,7 +208,9 @@ cdef class Aligner: def seq(self, str name, int start=0, int end=0x7fffffff): cdef int l - cdef char *s = cmappy.mappy_fetch_seq(self._idx, name.encode(), start, end, &l) + cdef char *s + if self._idx == NULL: return + s = cmappy.mappy_fetch_seq(self._idx, name.encode(), start, end, &l) if l == 0: return None r = s[:l] if isinstance(s, str) else s[:l].decode() free(s) @@ -224,6 +228,7 @@ cdef class Aligner: @property def seq_names(self): cdef char *p + if self._idx == NULL: return sn = [] for i in range(self._idx.n_seq): p = self._idx.seq[i].name From 58c2251b18e70cdaa2e8e2088899001cfe7d69ae Mon Sep 17 00:00:00 2001 From: Heng Li Date: Tue, 11 Jun 2019 09:16:03 -0400 Subject: [PATCH 03/14] compatibility with GenBank GTP (resolves $422) --- misc/paftools.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/misc/paftools.js b/misc/paftools.js index a4a8c0e..d7bea8c 100755 --- a/misc/paftools.js +++ b/misc/paftools.js @@ -1,6 +1,6 @@ #!/usr/bin/env k8 -var paftools_version = '2.17-r941'; +var paftools_version = '2.17-r949-dirty'; /***************************** ***** Library functions ***** @@ -1509,6 +1509,7 @@ function paf_gff2bed(args) var colors = { 'protein_coding':'0,128,255', + 'mRNA':'0,128,255', 'lincRNA':'0,192,0', 'snRNA':'0,192,0', 'miRNA':'0,192,0', @@ -1541,8 +1542,8 @@ function paf_gff2bed(args) print(a[0][0], st, en, name, 1000, a[0][3], cds_st, cds_en, color, a.length, sizes.join(",") + ",", starts.join(",") + ","); } - var re_gtf = /(transcript_id|transcript_type|transcript_biotype|gene_name|transcript_name) "([^"]+)";/g; - var re_gff3 = /(transcript_id|transcript_type|transcript_biotype|gene_name|transcript_name)=([^;]+)/g; + var re_gtf = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name) "([^"]+)";/g; + var re_gff3 = /\b(transcript_id|transcript_type|transcript_biotype|gene_name|gene_id|gbkey|transcript_name)=([^;]+)/g; var buf = new Bytes(); var file = args[getopt.ind] == '-'? new File() : new File(args[getopt.ind]); @@ -1559,19 +1560,19 @@ function paf_gff2bed(args) if (t[2] != "CDS" && t[2] != "exon") continue; t[3] = parseInt(t[3]) - 1; t[4] = parseInt(t[4]); - var id = null, type = "", gname = "N/A", biotype = "", m, tname = "N/A"; + var id = null, type = "", name = "N/A", biotype = "", m, tname = "N/A"; while ((m = re_gtf.exec(t[8])) != null) { if (m[1] == "transcript_id") id = m[2]; else if (m[1] == "transcript_type") type = m[2]; - else if (m[1] == "transcript_biotype") biotype = m[2]; - else if (m[1] == "gene_name") name = m[2]; + else if (m[1] == "transcript_biotype" || m[1] == "gbkey") biotype = m[2]; + else if (m[1] == "gene_name" || m[1] == "gene_id") name = m[2]; else if (m[1] == "transcript_name") tname = m[2]; } while ((m = re_gff3.exec(t[8])) != null) { if (m[1] == "transcript_id") id = m[2]; else if (m[1] == "transcript_type") type = m[2]; - else if (m[1] == "transcript_biotype") biotype = m[2]; - else if (m[1] == "gene_name") name = m[2]; + else if (m[1] == "transcript_biotype" || m[1] == "gbkey") biotype = m[2]; + else if (m[1] == "gene_name" || m[1] == "gene_id") name = m[2]; else if (m[1] == "transcript_name") tname = m[2]; } if (type == "" && biotype != "") type = biotype; From e026e1843960ec857614d43e4ec1a444187be6ce Mon Sep 17 00:00:00 2001 From: Heng Li Date: Mon, 1 Jul 2019 09:18:33 -0400 Subject: [PATCH 04/14] added the description of "SA" tag. Closes #438 --- minimap2.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/minimap2.1 b/minimap2.1 index 21b84bd..ff0b922 100644 --- a/minimap2.1 +++ b/minimap2.1 @@ -638,6 +638,7 @@ s2 i Chaining score of the best secondary chain NM i Total number of mismatches and gaps in the alignment MD Z To generate the ref sequence in the alignment AS i DP alignment score +SA Z List of other supplementary alignments ms i DP score of the max scoring segment in the alignment nn i Number of ambiguous bases in the alignment ts A Transcript strand (splice mode only) From 238b6bb3ea8a34bab1c66a005407bbea6953f29b Mon Sep 17 00:00:00 2001 From: Marcus Stoiber Date: Fri, 5 Jul 2019 12:23:53 -0700 Subject: [PATCH 05/14] Fix memory leak in mappy.aligner.map. --- python/mappy.pyx | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/python/mappy.pyx b/python/mappy.pyx index f9b9ffe..3273514 100644 --- a/python/mappy.pyx +++ b/python/mappy.pyx @@ -188,23 +188,30 @@ cdef class Aligner: _seq2 = seq2 if isinstance(seq2, bytes) else seq2.encode() regs = cmappy.mm_map_aux(self._idx, _seq, _seq2, &n_regs, b._b, &map_opt) - for i in range(n_regs): - cmappy.mm_reg2hitpy(self._idx, ®s[i], &h) - cigar, _cs, _MD = [], '', '' - for k in range(h.n_cigar32): # convert the 32-bit CIGAR encoding to Python array - c = h.cigar32[k] - cigar.append([c>>4, c&0xf]) - if cs or MD: # generate the cs and/or the MD tag, if requested - if cs: - l_cs_str = cmappy.mm_gen_cs(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq, 1) - _cs = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode() - if MD: - l_cs_str = cmappy.mm_gen_MD(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq) - _MD = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode() - yield Alignment(h.ctg, h.ctg_len, h.ctg_start, h.ctg_end, h.strand, h.qry_start, h.qry_end, h.mapq, cigar, h.is_primary, h.mlen, h.blen, h.NM, h.trans_strand, h.seg_id, _cs, _MD) - cmappy.mm_free_reg1(®s[i]) - free(regs) - free(cs_str) + try: + i = 0 + while i < n_regs: + cmappy.mm_reg2hitpy(self._idx, ®s[i], &h) + cigar, _cs, _MD = [], '', '' + for k in range(h.n_cigar32): # convert the 32-bit CIGAR encoding to Python array + c = h.cigar32[k] + cigar.append([c>>4, c&0xf]) + if cs or MD: # generate the cs and/or the MD tag, if requested + if cs: + l_cs_str = cmappy.mm_gen_cs(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq, 1) + _cs = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode() + if MD: + l_cs_str = cmappy.mm_gen_MD(km, &cs_str, &m_cs_str, self._idx, ®s[i], _seq) + _MD = cs_str[:l_cs_str] if isinstance(cs_str, str) else cs_str[:l_cs_str].decode() + yield Alignment(h.ctg, h.ctg_len, h.ctg_start, h.ctg_end, h.strand, h.qry_start, h.qry_end, h.mapq, cigar, h.is_primary, h.mlen, h.blen, h.NM, h.trans_strand, h.seg_id, _cs, _MD) + cmappy.mm_free_reg1(®s[i]) + i += 1 + finally: + while i < n_regs: + cmappy.mm_free_reg1(®s[i]) + i += 1 + free(regs) + free(cs_str) def seq(self, str name, int start=0, int end=0x7fffffff): cdef int l From 20c104ce8d014cc311844921c1fa265127b59778 Mon Sep 17 00:00:00 2001 From: John Marshall Date: Wed, 17 Jul 2019 11:43:54 +0100 Subject: [PATCH 06/14] Report errno on file opening failures and I/O errors Add the underlying operating system error (usually "No such file" or "Out of space" respectively, but highly informative when it is not) to these error messages. --- main.c | 7 ++++--- map.c | 3 ++- misc.c | 6 +++--- splitidx.c | 5 +++-- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/main.c b/main.c index 29257e4..9f9b5d7 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "bseq.h" #include "minimap.h" #include "mmpriv.h" @@ -172,7 +173,7 @@ int main(int argc, char *argv[]) else if (c == 'o') { if (strcmp(o.arg, "-") != 0) { if (freopen(o.arg, "wb", stdout) == NULL) { - fprintf(stderr, "[ERROR]\033[1;31m failed to write the output to file '%s'\033[0m\n", o.arg); + fprintf(stderr, "[ERROR]\033[1;31m failed to write the output to file '%s'\033[0m: %s\n", o.arg, strerror(errno)); exit(1); } } @@ -337,7 +338,7 @@ int main(int argc, char *argv[]) } idx_rdr = mm_idx_reader_open(argv[o.ind], &ipt, fnw); if (idx_rdr == 0) { - fprintf(stderr, "[ERROR] failed to open file '%s'\n", argv[o.ind]); + fprintf(stderr, "[ERROR] failed to open file '%s': %s\n", argv[o.ind], strerror(errno)); return 1; } if (!idx_rdr->is_idx && fnw == 0 && argc - o.ind < 2) { @@ -384,7 +385,7 @@ int main(int argc, char *argv[]) mm_split_merge(argc - (o.ind + 1), (const char**)&argv[o.ind + 1], &opt, n_parts); if (fflush(stdout) == EOF) { - fprintf(stderr, "[ERROR] failed to write the results\n"); + perror("[ERROR] failed to write the results"); exit(EXIT_FAILURE); } diff --git a/map.c b/map.c index d33405c..58e74fc 100644 --- a/map.c +++ b/map.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "kthread.h" #include "kvec.h" #include "kalloc.h" @@ -622,7 +623,7 @@ static mm_bseq_file_t **open_bseqs(int n, const char **fn) for (i = 0; i < n; ++i) { if ((fp[i] = mm_bseq_open(fn[i])) == 0) { if (mm_verbose >= 1) - fprintf(stderr, "ERROR: failed to open file '%s'\n", fn[i]); + fprintf(stderr, "ERROR: failed to open file '%s': %s\n", fn[i], strerror(errno)); for (j = 0; j < i; ++j) mm_bseq_close(fp[j]); free(fp); diff --git a/misc.c b/misc.c index f6b8c5f..ddfa9de 100644 --- a/misc.c +++ b/misc.c @@ -125,7 +125,7 @@ void mm_err_puts(const char *str) int ret; ret = puts(str); if (ret == EOF) { - fprintf(stderr, "[ERROR] failed to write the results\n"); + perror("[ERROR] failed to write the results"); exit(EXIT_FAILURE); } } @@ -135,7 +135,7 @@ void mm_err_fwrite(const void *p, size_t size, size_t nitems, FILE *fp) int ret; ret = fwrite(p, size, nitems, fp); if (ret == EOF) { - fprintf(stderr, "[ERROR] failed to write data\n"); + perror("[ERROR] failed to write data"); exit(EXIT_FAILURE); } } @@ -145,7 +145,7 @@ void mm_err_fread(void *p, size_t size, size_t nitems, FILE *fp) int ret; ret = fread(p, size, nitems, fp); if (ret == EOF) { - fprintf(stderr, "[ERROR] failed to read data\n"); + perror("[ERROR] failed to read data"); exit(EXIT_FAILURE); } } diff --git a/splitidx.c b/splitidx.c index 69f4864..507e498 100644 --- a/splitidx.c +++ b/splitidx.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "mmpriv.h" FILE *mm_split_init(const char *prefix, const mm_idx_t *mi) @@ -13,7 +14,7 @@ FILE *mm_split_init(const char *prefix, const mm_idx_t *mi) sprintf(fn, "%s.%.4d.tmp", prefix, mi->index); if ((fp = fopen(fn, "wb")) == NULL) { if (mm_verbose >= 1) - fprintf(stderr, "[ERROR]\033[1;31m failed to write to temporary file '%s'\033[0m\n", fn); + fprintf(stderr, "[ERROR]\033[1;31m failed to write to temporary file '%s'\033[0m: %s\n", fn, strerror(errno)); exit(1); } mm_err_fwrite(&k, 4, 1, fp); @@ -41,7 +42,7 @@ mm_idx_t *mm_split_merge_prep(const char *prefix, int n_splits, FILE **fp, uint3 sprintf(fn, "%s.%.4d.tmp", prefix, i); if ((fp[i] = fopen(fn, "rb")) == 0) { if (mm_verbose >= 1) - fprintf(stderr, "ERROR: failed to open temporary file '%s'\n", fn); + fprintf(stderr, "ERROR: failed to open temporary file '%s': %s\n", fn, strerror(errno)); for (j = 0; j < i; ++j) fclose(fp[j]); free(fn); From 7fc03b0c326ec2ad85a8cdaa9484a121f83c47ff Mon Sep 17 00:00:00 2001 From: Heng Li Date: Thu, 18 Jul 2019 09:13:30 -0400 Subject: [PATCH 07/14] r953: krealloc is buggy Its use in minimap2 didn't trigger the bug, so the older minimap2 is still ok. --- kalloc.c | 35 +++++++++++++++++++++-------------- kalloc.h | 10 ++++++++++ main.c | 2 +- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/kalloc.c b/kalloc.c index b36c333..8499552 100644 --- a/kalloc.c +++ b/kalloc.c @@ -18,15 +18,14 @@ * | | | | * p=p->ptr->ptr->ptr->ptr p->ptr p->ptr->ptr p->ptr->ptr->ptr */ - -#define MIN_CORE_SIZE 0x80000 - typedef struct header_t { size_t size; struct header_t *ptr; } header_t; typedef struct { + void *par; + size_t min_core_size; header_t base, *loop_head, *core_head; /* base is a zero-sized block always kept in the loop */ } kmem_t; @@ -36,31 +35,39 @@ static void panic(const char *s) abort(); } -void *km_init(void) +void *km_init2(void *km_par, size_t min_core_size) { - return calloc(1, sizeof(kmem_t)); + kmem_t *km; + km = (kmem_t*)kcalloc(km_par, 1, sizeof(kmem_t)); + km->par = km_par; + km->min_core_size = min_core_size > 0? min_core_size : 0x80000; + return (void*)km; } +void *km_init(void) { return km_init2(0, 0); } + void km_destroy(void *_km) { kmem_t *km = (kmem_t*)_km; + void *km_par; header_t *p, *q; if (km == NULL) return; + km_par = km->par; for (p = km->core_head; p != NULL;) { q = p->ptr; - free(p); + kfree(km_par, p); p = q; } - free(km); + kfree(km_par, km); } static header_t *morecore(kmem_t *km, size_t nu) { header_t *q; size_t bytes, *p; - nu = (nu + 1 + (MIN_CORE_SIZE - 1)) / MIN_CORE_SIZE * MIN_CORE_SIZE; /* the first +1 for core header */ + nu = (nu + 1 + (km->min_core_size - 1)) / km->min_core_size * km->min_core_size; /* the first +1 for core header */ bytes = nu * sizeof(header_t); - q = (header_t*)malloc(bytes); + q = (header_t*)kmalloc(km->par, bytes); if (!q) panic("[morecore] insufficient memory"); q->ptr = km->core_head, q->size = nu, km->core_head = q; p = (size_t*)(q + 1); @@ -125,7 +132,7 @@ void *kmalloc(void *_km, size_t n_bytes) if (n_bytes == 0) return 0; if (km == NULL) return malloc(n_bytes); - n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t) + 1; + n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t); /* header+n_bytes requires at least this number of units */ if (!(q = km->loop_head)) /* the first time when kmalloc() is called, intialize it */ q = km->loop_head = km->base.ptr = &km->base; @@ -160,18 +167,18 @@ void *kcalloc(void *_km, size_t count, size_t size) void *krealloc(void *_km, void *ap, size_t n_bytes) // TODO: this can be made more efficient in principle { kmem_t *km = (kmem_t*)_km; - size_t n_units, *p, *q; + size_t cap, *p, *q; if (n_bytes == 0) { kfree(km, ap); return 0; } if (km == NULL) return realloc(ap, n_bytes); if (ap == NULL) return kmalloc(km, n_bytes); - n_units = (n_bytes + sizeof(size_t) + sizeof(header_t) - 1) / sizeof(header_t); p = (size_t*)ap - 1; - if (*p >= n_units) return ap; /* TODO: this prevents shrinking */ + cap = (*p) * sizeof(header_t) - sizeof(size_t); + if (cap >= n_bytes) return ap; /* TODO: this prevents shrinking */ q = (size_t*)kmalloc(km, n_bytes); - memcpy(q, ap, (*p - 1) * sizeof(header_t)); + memcpy(q, ap, cap); kfree(km, ap); return q; } diff --git a/kalloc.h b/kalloc.h index e891892..6d72e4e 100644 --- a/kalloc.h +++ b/kalloc.h @@ -17,6 +17,7 @@ void *kcalloc(void *km, size_t count, size_t size); void kfree(void *km, void *ptr); void *km_init(void); +void *km_init2(void *km_par, size_t min_core_size); void km_destroy(void *km); void km_stat(const void *_km, km_stat_t *s); @@ -24,4 +25,13 @@ void km_stat(const void *_km, km_stat_t *s); } #endif +#define KMALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kmalloc((km), (len) * sizeof(*(ptr)))) +#define KCALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))kcalloc((km), (len), sizeof(*(ptr)))) +#define KREALLOC(km, ptr, len) ((ptr) = (__typeof__(ptr))krealloc((km), (ptr), (len) * sizeof(*(ptr)))) + +#define KEXPAND(km, a, m) do { \ + (m) = (m) >= 4? (m) + ((m)>>1) : 16; \ + KREALLOC((km), (a), (m)); \ + } while (0) + #endif diff --git a/main.c b/main.c index 9f9b5d7..2a1ff15 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,7 @@ #include "mmpriv.h" #include "ketopt.h" -#define MM_VERSION "2.17-r943-dirty" +#define MM_VERSION "2.17-r953-dirty" #ifdef __linux__ #include From d90583b83cd81abd652abb025f39b8884937d59c Mon Sep 17 00:00:00 2001 From: Heng Li Date: Thu, 18 Jul 2019 09:17:08 -0400 Subject: [PATCH 08/14] r954: fixed two potential undef behaviors (#443) --- chain.c | 4 ++-- main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/chain.c b/chain.c index be9d51b..95abf5e 100644 --- a/chain.c +++ b/chain.c @@ -155,8 +155,8 @@ mm128_t *mm_chain_dp(int max_dist_x, int max_dist_y, int bw, int max_skip, int m memcpy(&a[k], &b[w[i].y>>32], n * sizeof(mm128_t)); k += n; } - memcpy(u, u2, n_u * 8); - memcpy(b, a, k * sizeof(mm128_t)); // write _a_ to _b_ and deallocate _a_ because _a_ is oversized, sometimes a lot + if (n_u) memcpy(u, u2, n_u * 8); + if (k) memcpy(b, a, k * sizeof(mm128_t)); // write _a_ to _b_ and deallocate _a_ because _a_ is oversized, sometimes a lot kfree(km, a); kfree(km, w); kfree(km, u2); return b; } diff --git a/main.c b/main.c index 2a1ff15..84a536b 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,7 @@ #include "mmpriv.h" #include "ketopt.h" -#define MM_VERSION "2.17-r953-dirty" +#define MM_VERSION "2.17-r954-dirty" #ifdef __linux__ #include From a3e7a575fb8b2a046f4f99ce3cb09f0418c179c5 Mon Sep 17 00:00:00 2001 From: Torsten Seemann Date: Mon, 4 Nov 2019 07:38:10 +1100 Subject: [PATCH 09/14] Add splice:hq to --help --- main.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index 84a536b..a5633c2 100644 --- a/main.c +++ b/main.c @@ -323,11 +323,11 @@ int main(int argc, char *argv[]) fprintf(fp_help, " --version show version number\n"); fprintf(fp_help, " Preset:\n"); fprintf(fp_help, " -x STR preset (always applied before other options; see minimap2.1 for details) []\n"); - fprintf(fp_help, " - map-pb/map-ont: PacBio/Nanopore vs reference mapping\n"); - fprintf(fp_help, " - ava-pb/ava-ont: PacBio/Nanopore read overlap\n"); - fprintf(fp_help, " - asm5/asm10/asm20: asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\n"); - fprintf(fp_help, " - splice: long-read spliced alignment\n"); - fprintf(fp_help, " - sr: genomic short-read mapping\n"); + fprintf(fp_help, " - map-pb/map-ont - PacBio/Nanopore vs reference mapping\n"); + fprintf(fp_help, " - ava-pb/ava-ont - PacBio/Nanopore read overlap\n"); + fprintf(fp_help, " - asm5/asm10/asm20 - asm-to-ref mapping, for ~0.1/1/5%% sequence divergence\n"); + fprintf(fp_help, " - splice/splice:hq - long-read/Pacbio-CCS spliced alignment\n"); + fprintf(fp_help, " - sr - genomic short-read mapping\n"); fprintf(fp_help, "\nSee `man ./minimap2.1' for detailed description of these and other advanced command-line options.\n"); return fp_help == stdout? 0 : 1; } From 081df6ac7df97c43f2d45a1d62840a62bdf03683 Mon Sep 17 00:00:00 2001 From: xdudiagnoa <47234985+xdudiagnoa@users.noreply.github.com> Date: Mon, 16 Sep 2019 17:21:40 +0800 Subject: [PATCH 10/14] Fix example.c seq read logic for every idx should map all input seqs --- example.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example.c b/example.c index 80e493c..ca1fdbe 100644 --- a/example.c +++ b/example.c @@ -35,6 +35,8 @@ int main(int argc, char *argv[]) while ((mi = mm_idx_reader_read(r, n_threads)) != 0) { // traverse each part of the index mm_mapopt_update(&mopt, mi); // this sets the maximum minimizer occurrence; TODO: set a better default in mm_mapopt_init()! mm_tbuf_t *tbuf = mm_tbuf_init(); // thread buffer; for multi-threading, allocate one tbuf for each thread + gzrewind(f); + kseq_rewind(ks); while (kseq_read(ks) >= 0) { // each kseq_read() call reads one query sequence mm_reg1_t *reg; int j, i, n_reg; From 367aed427104eb6eb2d4afaed43608a9772b6f09 Mon Sep 17 00:00:00 2001 From: Heng Li Date: Mon, 23 Dec 2019 17:33:10 -0500 Subject: [PATCH 11/14] added the asan and tsan targets to Makefile --- Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Makefile b/Makefile index ed341f6..18622f5 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,16 @@ else #if aarch64 is defined endif endif +ifneq ($(asan),) + CFLAGS+=-fsanitize=address + LIBS+=-fsanitize=address +endif + +ifneq ($(tsan),) + CFLAGS+=-fsanitize=thread + LIBS+=-fsanitize=thread +endif + .PHONY:all extra clean depend .SUFFIXES:.c .o From 47b646acbf0e551dd80411545b72439c9ed69f98 Mon Sep 17 00:00:00 2001 From: Heng Li Date: Mon, 6 Jan 2020 21:13:33 -0500 Subject: [PATCH 12/14] r961: print indexed length --- index.c | 4 ++-- main.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.c b/index.c index 164e8e5..6a49bb1 100644 --- a/index.c +++ b/index.c @@ -117,8 +117,8 @@ void mm_idx_stat(const mm_idx_t *mi) if (kh_key(h, k)&1) ++n1; } } - fprintf(stderr, "[M::%s::%.3f*%.2f] distinct minimizers: %d (%.2f%% are singletons); average occurrences: %.3lf; average spacing: %.3lf\n", - __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), n, 100.0*n1/n, (double)sum / n, (double)len / sum); + fprintf(stderr, "[M::%s::%.3f*%.2f] distinct minimizers: %d (%.2f%% are singletons); average occurrences: %.3lf; average spacing: %.3lf; total length: %ld\n", + __func__, realtime() - mm_realtime0, cputime() / (realtime() - mm_realtime0), n, 100.0*n1/n, (double)sum / n, (double)len / sum, (long)len); } int mm_idx_index_name(mm_idx_t *mi) diff --git a/main.c b/main.c index a5633c2..1b1fa81 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,7 @@ #include "mmpriv.h" #include "ketopt.h" -#define MM_VERSION "2.17-r954-dirty" +#define MM_VERSION "2.17-r961-dirty" #ifdef __linux__ #include From 3c0d05d272b957289c5525790f718626131c2a96 Mon Sep 17 00:00:00 2001 From: Heng Li Date: Mon, 6 Jan 2020 21:53:21 -0500 Subject: [PATCH 13/14] r962: abort given wrong RG line; resolves #541 --- format.c | 12 ++++++++---- main.c | 12 +++++++++--- mmpriv.h | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/format.c b/format.c index 6d9e7ab..0dd943a 100644 --- a/format.c +++ b/format.c @@ -79,11 +79,11 @@ static char *mm_escape(char *s) return s; } -static void sam_write_rg_line(kstring_t *str, const char *s) +static int sam_write_rg_line(kstring_t *str, const char *s) { char *p, *q, *r, *rg_line = 0; memset(mm_rg_id, 0, 256); - if (s == 0) return; + if (s == 0) return 0; if (strstr(s, "@RG") != s) { if (mm_verbose >= 1) fprintf(stderr, "[ERROR] the read group line is not started with @RG\n"); goto err_set_rg; @@ -108,20 +108,23 @@ static void sam_write_rg_line(kstring_t *str, const char *s) for (q = p, r = mm_rg_id; *q && *q != '\t' && *q != '\n'; ++q) *r++ = *q; mm_sprintf_lite(str, "%s\n", rg_line); + return 0; err_set_rg: free(rg_line); + return -1; } -void mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int argc, char *argv[]) +int mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int argc, char *argv[]) { kstring_t str = {0,0,0}; + int ret = 0; if (idx) { uint32_t i; for (i = 0; i < idx->n_seq; ++i) mm_sprintf_lite(&str, "@SQ\tSN:%s\tLN:%d\n", idx->seq[i].name, idx->seq[i].len); } - if (rg) sam_write_rg_line(&str, rg); + if (rg) ret = sam_write_rg_line(&str, rg); mm_sprintf_lite(&str, "@PG\tID:minimap2\tPN:minimap2"); if (ver) mm_sprintf_lite(&str, "\tVN:%s", ver); if (argc > 1) { @@ -132,6 +135,7 @@ void mm_write_sam_hdr(const mm_idx_t *idx, const char *rg, const char *ver, int } mm_err_puts(str.s); free(str.s); + return ret; } static void write_cs_core(kstring_t *s, const uint8_t *tseq, const uint8_t *qseq, const mm_reg1_t *r, char *tmp, int no_iden, int write_tag) diff --git a/main.c b/main.c index 1b1fa81..2d8726e 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,7 @@ #include "mmpriv.h" #include "ketopt.h" -#define MM_VERSION "2.17-r961-dirty" +#define MM_VERSION "2.17-r962-dirty" #ifdef __linux__ #include @@ -356,13 +356,19 @@ int main(int argc, char *argv[]) return 1; } if ((opt.flag & MM_F_OUT_SAM) && idx_rdr->n_parts == 1) { + int ret; if (mm_idx_reader_eof(idx_rdr)) { - mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv); + ret = mm_write_sam_hdr(mi, rg, MM_VERSION, argc, argv); } else { - mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv); + ret = mm_write_sam_hdr(0, rg, MM_VERSION, argc, argv); if (opt.split_prefix == 0 && mm_verbose >= 2) fprintf(stderr, "[WARNING]\033[1;31m For a multi-part index, no @SQ lines will be outputted. Please use --split-prefix.\033[0m\n"); } + if (ret != 0) { + mm_idx_destroy(mi); + mm_idx_reader_close(idx_rdr); + return 1; + } } if (mm_verbose >= 3) fprintf(stderr, "[M::%s::%.3f*%.2f] loaded/built the index for %d target sequence(s)\n", diff --git a/mmpriv.h b/mmpriv.h index c9b91cd..c1164e2 100644 --- a/mmpriv.h +++ b/mmpriv.h @@ -59,7 +59,7 @@ uint32_t ks_ksmall_uint32_t(size_t n, uint32_t arr[], size_t kk); void mm_sketch(void *km, const char *str, int len, int w, int k, uint32_t rid, int is_hpc, mm128_v *p); -void mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]); +int mm_write_sam_hdr(const mm_idx_t *mi, const char *rg, const char *ver, int argc, char *argv[]); void mm_write_paf(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int opt_flag); void mm_write_paf3(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, void *km, int opt_flag, int rep_len); void mm_write_sam(kstring_t *s, const mm_idx_t *mi, const mm_bseq1_t *t, const mm_reg1_t *r, int n_regs, const mm_reg1_t *regs); From cdb7857841fa472f26c7575ba3c51682af5c885a Mon Sep 17 00:00:00 2001 From: Heng Li Date: Mon, 6 Jan 2020 22:03:50 -0500 Subject: [PATCH 14/14] r963: --junc-bonus not working; resolves #513 --- main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 2d8726e..63730c1 100644 --- a/main.c +++ b/main.c @@ -7,7 +7,7 @@ #include "mmpriv.h" #include "ketopt.h" -#define MM_VERSION "2.17-r962-dirty" +#define MM_VERSION "2.17-r963-dirty" #ifdef __linux__ #include @@ -209,6 +209,7 @@ int main(int argc, char *argv[]) else if (c == 337) opt.max_sw_mat = mm_parse_num(o.arg); // --cap-sw-mat else if (c == 338) opt.max_qlen = mm_parse_num(o.arg); // --max-qlen else if (c == 340) junc_bed = o.arg; // --junc-bed + else if (c == 341) opt.junc_bonus = atoi(o.arg); // --junc-bonus else if (c == 342) opt.flag |= MM_F_SAM_HIT_ONLY; // --sam-hit-only else if (c == 314) { // --frag yes_or_no(&opt, MM_F_FRAG_MODE, o.longidx, o.arg, 1);