minimap2 0.2.30.3 → 1.2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +48 -63
  3. data/ext/minimap2/Makefile +1 -1
  4. data/ext/minimap2/format.c +12 -2
  5. data/ext/minimap2/hit.c +19 -8
  6. data/ext/minimap2/ksw2_ll_sse.c +2 -2
  7. data/ext/minimap2/minimap.h +2 -1
  8. data/ext/minimap2/pe.c +7 -2
  9. data/ext/ruby_minimap2/extconf.rb +47 -0
  10. data/ext/ruby_minimap2/native_main.c +15 -0
  11. data/ext/ruby_minimap2/ruby_minimap2.c +1134 -0
  12. data/lib/minimap2/aligner.rb +66 -374
  13. data/lib/minimap2/alignment.rb +22 -11
  14. data/lib/minimap2/version.rb +2 -1
  15. data/lib/minimap2.rb +39 -110
  16. metadata +8 -89
  17. data/ext/Rakefile +0 -60
  18. data/ext/cmappy/cmappy.c +0 -134
  19. data/ext/cmappy/cmappy.h +0 -46
  20. data/ext/minimap2/FAQ.md +0 -46
  21. data/ext/minimap2/MANIFEST.in +0 -10
  22. data/ext/minimap2/Makefile.simde +0 -97
  23. data/ext/minimap2/NEWS.md +0 -989
  24. data/ext/minimap2/README.md +0 -428
  25. data/ext/minimap2/code_of_conduct.md +0 -30
  26. data/ext/minimap2/cookbook.md +0 -243
  27. data/ext/minimap2/minimap2.1 +0 -844
  28. data/ext/minimap2/misc/README.md +0 -180
  29. data/ext/minimap2/misc/pafcluster.js +0 -241
  30. data/ext/minimap2/misc/paftools.js +0 -3734
  31. data/ext/minimap2/pyproject.toml +0 -2
  32. data/ext/minimap2/python/README.rst +0 -198
  33. data/ext/minimap2/python/cmappy.h +0 -152
  34. data/ext/minimap2/python/cmappy.pxd +0 -156
  35. data/ext/minimap2/python/mappy.pyx +0 -289
  36. data/ext/minimap2/python/minimap2.py +0 -41
  37. data/ext/minimap2/setup.py +0 -55
  38. data/ext/minimap2/test/MT-human.fa +0 -278
  39. data/ext/minimap2/test/MT-orang.fa +0 -276
  40. data/ext/minimap2/test/q-inv.fa +0 -4
  41. data/ext/minimap2/test/q2.fa +0 -2
  42. data/ext/minimap2/test/t-inv.fa +0 -127
  43. data/ext/minimap2/test/t2.fa +0 -2
  44. data/ext/minimap2/test/x3s-aln.txt +0 -5
  45. data/ext/minimap2/test/x3s-qry.fa +0 -5
  46. data/ext/minimap2/test/x3s-ref.fa +0 -10
  47. data/ext/minimap2/tex/Makefile +0 -21
  48. data/ext/minimap2/tex/bioinfo.cls +0 -930
  49. data/ext/minimap2/tex/blasr-mc.eval +0 -17
  50. data/ext/minimap2/tex/bowtie2-s3.sam.eval +0 -28
  51. data/ext/minimap2/tex/bwa-s3.sam.eval +0 -52
  52. data/ext/minimap2/tex/bwa.eval +0 -55
  53. data/ext/minimap2/tex/eval2roc.pl +0 -33
  54. data/ext/minimap2/tex/graphmap.eval +0 -4
  55. data/ext/minimap2/tex/hs38-simu.sh +0 -10
  56. data/ext/minimap2/tex/minialign.eval +0 -49
  57. data/ext/minimap2/tex/minimap2.bib +0 -460
  58. data/ext/minimap2/tex/minimap2.tex +0 -724
  59. data/ext/minimap2/tex/mm2-s3.sam.eval +0 -62
  60. data/ext/minimap2/tex/mm2-update.tex +0 -240
  61. data/ext/minimap2/tex/mm2.approx.eval +0 -12
  62. data/ext/minimap2/tex/mm2.eval +0 -13
  63. data/ext/minimap2/tex/natbib.bst +0 -1288
  64. data/ext/minimap2/tex/natbib.sty +0 -803
  65. data/ext/minimap2/tex/ngmlr.eval +0 -38
  66. data/ext/minimap2/tex/roc.gp +0 -60
  67. data/ext/minimap2/tex/snap-s3.sam.eval +0 -62
  68. data/ext/minimap2.patch +0 -19
  69. data/lib/minimap2/ffi/constants.rb +0 -267
  70. data/lib/minimap2/ffi/functions.rb +0 -239
  71. data/lib/minimap2/ffi/mappy.rb +0 -104
  72. data/lib/minimap2/ffi.rb +0 -27
@@ -1,180 +0,0 @@
1
- ## <a name="started"></a>Getting Started
2
-
3
- ```sh
4
- # install minimap2
5
- git clone https://github.com/lh3/minimap2
6
- cd minimap2 && make
7
- # install the k8 javascript shell
8
- curl -L https://github.com/attractivechaos/k8/releases/download/v0.2.4/k8-0.2.4.tar.bz2 | tar -jxf -
9
- cp k8-0.2.4/k8-`uname -s` k8 # or copy it to a directory on your $PATH
10
- # export PATH="$PATH:`pwd`:`pwd`/misc" # run this if k8, minimap2 or paftools.js not on your $PATH
11
- minimap2 --cs test/MT-human.fa test/MT-orang.fa | paftools.js view - # view alignment
12
- minimap2 -c test/MT-human.fa test/MT-orang.fa | paftools.js stat - # basic alignment statistics
13
- minimap2 -c --cs test/MT-human.fa test/MT-orang.fa \
14
- | sort -k6,6 -k8,8n | paftools.js call -L15000 - # calling variants from asm-to-ref alignment
15
- minimap2 -c test/MT-human.fa test/MT-orang.fa \
16
- | paftools.js liftover -l10000 - <(echo -e "MT_orang\t2000\t5000") # liftOver
17
- # no test data for the following examples
18
- paftools.js junceval -e anno.gtf splice.sam > out.txt # compare splice junctions to annotations
19
- paftools.js splice2bed splice.sam > splice.bed # convert PAF/SAM to BED12
20
- paftools.js gff2bed anno.gtf > anno.bed # convert GTF/GFF3 to BED12
21
- ```
22
-
23
- ## Table of Contents
24
-
25
- - [Getting Started](#started)
26
- - [Introduction](#intro)
27
- - [Evaluation](#eval)
28
- - [Evaluating mapping accuracy with simulated reads](#mapeval)
29
- - [Evaluating read overlap sensitivity](#oveval)
30
- - [Calling Variants from Assemblies](#asmvar)
31
-
32
- ## <a name="intro"></a>Introduction
33
-
34
- paftools.js is a script that processes alignments in the [PAF format][paf],
35
- such as converting between formats, evaluating mapping accuracy, lifting over
36
- BED files based on alignment, and calling variants from assembly-to-assembly
37
- alignment. This script *requires* the [k8 Javascript shell][k8] to run. On
38
- Linux or Mac, you can download the precompiled k8 binary with:
39
-
40
- ```sh
41
- curl -L https://github.com/attractivechaos/k8/releases/download/v0.2.4/k8-0.2.4.tar.bz2 | tar -jxf -
42
- cp k8-0.2.4/k8-`uname -s` $HOME/bin/k8 # assuming $HOME/bin in your $PATH
43
- ```
44
-
45
- It is highly recommended to copy the executable `k8` to a directory on your
46
- `$PATH` such as `/usr/bin/env` can find it. Like python scripts, once you
47
- install `k8`, you can launch paftools.js in one of the two ways:
48
-
49
- ```sh
50
- path/to/paftools.js # only if k8 is on your $PATH
51
- k8 path/to/paftools.js
52
- ```
53
-
54
- In a nutshell, paftools.js has the following commands:
55
-
56
- ```
57
- Usage: paftools.js <command> [arguments]
58
- Commands:
59
- view convert PAF to BLAST-like (for eyeballing) or MAF
60
- splice2bed convert spliced alignment in PAF/SAM to BED12
61
- sam2paf convert SAM to PAF
62
- delta2paf convert MUMmer's delta to PAF
63
- gff2bed convert GTF/GFF3 to BED12
64
-
65
- stat collect basic mapping information in PAF/SAM
66
- liftover simplistic liftOver
67
- call call variants from asm-to-ref alignment with the cs tag
68
- bedcov compute the number of bases covered
69
-
70
- mapeval evaluate mapping accuracy using mason2/PBSIM-simulated FASTQ
71
- mason2fq convert mason2-simulated SAM to FASTQ
72
- pbsim2fq convert PBSIM-simulated MAF to FASTQ
73
- junceval evaluate splice junction consistency with known annotations
74
- ov-eval evaluate read overlap sensitivity using read-to-ref mapping
75
- ```
76
-
77
- paftools.js seamlessly reads both plain text files and gzip'd text files.
78
-
79
- ## <a name="eval"></a>Evaluation
80
-
81
- ### <a name="mapeval"></a>Evaluating mapping accuracy with simulated reads
82
-
83
- The **pbsim2fq** command of paftools.js converts the MAF output of [pbsim][pbsim]
84
- to FASTQ and encodes the true mapping position in the read name in a format like
85
- `S1_33!chr1!225258409!225267761!-`. Similarly, the **mason2fq** command
86
- converts [mason2][mason2] simulated SAM to FASTQ.
87
-
88
- Command **mapeval** evaluates mapped SAM/PAF. Here is example output:
89
-
90
- ```
91
- Q 60 32478 0 0.000000000 32478
92
- Q 22 16 1 0.000030775 32494
93
- Q 21 43 1 0.000061468 32537
94
- Q 19 73 1 0.000091996 32610
95
- Q 14 66 1 0.000122414 32676
96
- Q 10 27 3 0.000214048 32703
97
- Q 8 14 1 0.000244521 32717
98
- Q 7 13 2 0.000305530 32730
99
- Q 6 46 1 0.000335611 32776
100
- Q 3 10 1 0.000366010 32786
101
- Q 2 20 2 0.000426751 32806
102
- Q 1 248 94 0.003267381 33054
103
- Q 0 31 17 0.003778147 33085
104
- U 3
105
- ```
106
-
107
- where each Q-line gives the quality threshold, the number of reads mapped with
108
- mapping quality equal to or greater than the threshold, number of wrong
109
- mappings, accumulative mapping error rate and the accumulative number of
110
- mapped reads. The U-line, if present, gives the number of unmapped reads if
111
- they are present in the SAM file.
112
-
113
- Suppose the reported mapping coordinate overlap with the true coordinate like
114
- the following:
115
-
116
- ```
117
- truth: --------------------
118
- mapper: ----------------------
119
- |<- l1 ->|<-- o -->|<-- l2 -->|
120
- ```
121
-
122
- Let `r=o/(l1+o+l2)`. The reported mapping is considered correct if `r>0.1` by
123
- default.
124
-
125
- ### <a name="oveval"></a>Evaluating read overlap sensitivity
126
-
127
- Command **ov-eval** takes *sorted* read-to-reference alignment and read
128
- overlaps in PAF as input, and evaluates the sensitivity. For example:
129
-
130
- ```sh
131
- minimap2 -cx map-pb ref.fa reads.fq.gz | sort -k6,6 -k8,8n > reads-to-ref.paf
132
- minimap2 -x ava-pb reads.fq.gz reads.fq.gz > ovlp.paf
133
- k8 ov-eval.js reads-to-ref.paf ovlp.paf
134
- ```
135
-
136
- ## <a name="asmvar"></a>Calling Variants from Haploid Assemblies
137
-
138
- The **call** command of paftools.js calls variants from coordinate-sorted
139
- assembly-to-reference alignment. It calls variants from the [cs tag][cs] and
140
- identifies confident/callable regions as those covered by exactly one contig.
141
- Here are example command lines:
142
-
143
- ```sh
144
- minimap2 -cx asm5 -t8 --cs ref.fa asm.fa > asm.paf # keeping this file is recommended; --cs required!
145
- sort -k6,6 -k8,8n asm.paf > asm.srt.paf # sort by reference start coordinate
146
- k8 paftools.js call asm.srt.paf > asm.var.txt
147
- ```
148
-
149
- Here is sample output:
150
-
151
- ```
152
- V chr1 2276040 2276041 1 60 c g LJII01000171.1 1217409 1217410 +
153
- V chr1 2280409 2280410 1 60 a g LJII01000171.1 1221778 1221779 +
154
- V chr1 2280504 2280505 1 60 a g LJII01000171.1 1221873 1221874 +
155
- R chr1 2325140 2436340
156
- V chr1 2325287 2325287 1 60 - ct LJII01000171.1 1272894 1272896 +
157
- V chr1 2325642 2325644 1 60 tt - LJII01000171.1 1273251 1273251 +
158
- V chr1 2326051 2326052 1 60 c t LJII01000171.1 1273658 1273659 +
159
- V chr1 2326287 2326288 1 60 c t LJII01000171.1 1273894 1273895 +
160
- ```
161
-
162
- where a line starting with `R` gives regions covered by one query contig, and a
163
- V-line encodes a variant in the following format: chr, start, end, query depth,
164
- mapping quality, REF allele, ALT allele, query name, query start, end and the
165
- query orientation. Generally, you should only look at variants where column 5
166
- is one.
167
-
168
- By default, when calling variants, "paftools.js call" ignores alignments 50kb
169
- or shorter; when deriving callable regions, it ignores alignments 10kb or
170
- shorter. It uses two thresholds to avoid edge effects. These defaults are
171
- designed for long-read assemblies. For short reads, both should be reduced.
172
-
173
-
174
-
175
- [paf]: https://github.com/lh3/miniasm/blob/master/PAF.md
176
- [cs]: https://github.com/lh3/minimap2#cs
177
- [k8]: https://github.com/attractivechaos/k8
178
- [maf]: https://genome.ucsc.edu/FAQ/FAQformat#format5
179
- [pbsim]: https://github.com/pfaucon/PBSIM-PacBio-Simulator
180
- [mason2]: https://github.com/seqan/seqan/tree/master/apps/mason2
@@ -1,241 +0,0 @@
1
- #!/usr/bin/env k8
2
-
3
- "use strict";
4
-
5
- Array.prototype.delete_at = function(i) {
6
- for (let j = i; j < this.length - 1; ++j)
7
- this[j] = this[j + 1];
8
- --this.length;
9
- }
10
-
11
- function* getopt(argv, ostr, longopts) {
12
- if (argv.length == 0) return;
13
- let pos = 0, cur = 0;
14
- while (cur < argv.length) {
15
- let lopt = "", opt = "?", arg = "";
16
- while (cur < argv.length) { // skip non-option arguments
17
- if (argv[cur][0] == "-" && argv[cur].length > 1) {
18
- if (argv[cur] == "--") cur = argv.length;
19
- break;
20
- } else ++cur;
21
- }
22
- if (cur == argv.length) break;
23
- let a = argv[cur];
24
- if (a[0] == "-" && a[1] == "-") { // a long option
25
- pos = -1;
26
- let c = 0, k = -1, tmp = "", o;
27
- const pos_eq = a.indexOf("=");
28
- if (pos_eq > 0) {
29
- o = a.substring(2, pos_eq);
30
- arg = a.substring(pos_eq + 1);
31
- } else o = a.substring(2);
32
- for (let i = 0; i < longopts.length; ++i) {
33
- let y = longopts[i];
34
- if (y[y.length - 1] == "=") y = y.substring(0, y.length - 1);
35
- if (o.length <= y.length && o == y.substring(0, o.length)) {
36
- k = i, tmp = y;
37
- ++c; // c is the number of matches
38
- if (o == y) { // exact match
39
- c = 1;
40
- break;
41
- }
42
- }
43
- }
44
- if (c == 1) { // find a unique match
45
- lopt = tmp;
46
- if (pos_eq < 0 && longopts[k][longopts[k].length-1] == "=" && cur + 1 < argv.length) {
47
- arg = argv[cur+1];
48
- argv.delete_at(cur + 1);
49
- }
50
- }
51
- } else { // a short option
52
- if (pos == 0) pos = 1;
53
- opt = a[pos++];
54
- let k = ostr.indexOf(opt);
55
- if (k < 0) {
56
- opt = "?";
57
- } else if (k + 1 < ostr.length && ostr[k+1] == ":") { // requiring an argument
58
- if (pos >= a.length) {
59
- arg = argv[cur+1];
60
- argv.delete_at(cur + 1);
61
- } else arg = a.substring(pos);
62
- pos = -1;
63
- }
64
- }
65
- if (pos < 0 || pos >= argv[cur].length) {
66
- argv.delete_at(cur);
67
- pos = 0;
68
- }
69
- if (lopt != "") yield { opt: `--${lopt}`, arg: arg };
70
- else if (opt != "?") yield { opt: `-${opt}`, arg: arg };
71
- else yield { opt: "?", arg: "" };
72
- }
73
- }
74
-
75
- function* k8_readline(fn) {
76
- let buf = new Bytes();
77
- let file = new File(fn);
78
- while (file.readline(buf) >= 0) {
79
- yield buf.toString();
80
- }
81
- file.close();
82
- buf.destroy();
83
- }
84
-
85
- function merge_hits(b) {
86
- if (b.length == 1)
87
- return { name1:b[0].name1, name2:b[0].name2, len1:b[0].len1, len2:b[0].len2, min_cov:b[0].min_cov, max_cov:b[0].max_cov, cov1:b[0].cov1, cov2:b[0].cov2, s1:b[0].s1, dv:b[0].dv };
88
- b.sort(function(x, y) { return x.st1 - y.st1 });
89
- let f = [], bt = [];
90
- for (let i = 0; i < b.length; ++i)
91
- f[i] = b[i].s1, bt[i] = -1;
92
- for (let i = 0; i < b.length; ++i) {
93
- for (let j = 0; j < i; ++j) {
94
- if (b[j].st2 < b[i].st2) {
95
- if (b[j].en1 >= b[i].en1) continue;
96
- if (b[j].en2 >= b[i].en2) continue;
97
- const ov1 = b[j].en1 <= b[i].st1? 0 : b[i].st1 - b[j].en1;
98
- const li1 = b[i].en1 - b[i].st1;
99
- const s11 = b[i].s1 / li1 * (li1 - ov1);
100
- const ov2 = b[j].en2 <= b[i].st2? 0 : b[i].st2 - b[j].en2;
101
- const li2 = b[i].en2 - b[i].st2;
102
- const s12 = b[i].s1 / li2 * (li2 - ov2);
103
- const s1 = s11 < s12? s11 : s12;
104
- if (f[i] < f[j] + s1)
105
- f[i] = f[j] + s1, bt[i] = j;
106
- }
107
- }
108
- }
109
- let max_i = -1, max_f = 0, d = [];
110
- for (let i = 0; i < b.length; ++i)
111
- if (max_f < f[i])
112
- max_f = f[i], max_i = i;
113
- for (let k = max_i; k >= 0; k = bt[k])
114
- d.push(k);
115
- d = d.reverse();
116
- let dv = 0, tot = 0, cov1 = 0, cov2 = 0, st1 = 0, en1 = 0, st2 = 0, en2 = 0;
117
- for (let k = 0; k < d.length; ++k) {
118
- const i = d[k];
119
- tot += b[i].blen;
120
- dv += b[i].dv * b[i].blen;
121
- if (b[i].st1 > en1) {
122
- cov1 += en1 - st1;
123
- st1 = b[i].st1, en1 = b[i].en1;
124
- } else en1 = en1 > b[i].en1? en1 : b[i].en1;
125
- if (b[i].st2 > en2) {
126
- cov2 += en2 - st2;
127
- st2 = b[i].st2, en2 = b[i].en2;
128
- } else en2 = en2 > b[i].en2? en2 : b[i].en2;
129
- }
130
- dv /= tot;
131
- cov1 = (cov1 + (en1 - st1)) / b[0].len1;
132
- cov2 = (cov2 + (en2 - st2)) / b[0].len2;
133
- const min_cov = cov1 < cov2? cov1 : cov2;
134
- const max_cov = cov1 > cov2? cov1 : cov2;
135
- //warn(d.length, b[0].name1, b[0].name2, min_cov, max_cov);
136
- return { name1:b[0].name1, name2:b[0].name2, len1:b[0].len1, len2:b[0].len2, min_cov:min_cov, max_cov:max_cov, cov1:cov1, cov2:cov2, s1:max_f, dv:dv };
137
- }
138
-
139
- function main(args) {
140
- let opt = { min_cov:.9, max_dv:.015, max_diff:20000 };
141
- for (const o of getopt(args, "c:d:e:", [])) {
142
- if (o.opt == '-c') opt.min_cov = parseFloat(o.arg);
143
- else if (o.opt == '-d') opt.max_dv = parseFloat(o.arg);
144
- else if (o.opt == '-e') opt.max_diff = parseFloat(o.arg);
145
- }
146
- if (args.length == 0) {
147
- print("Usage: pafcluster.js [options] <ava.paf>");
148
- print("Options:");
149
- print(` -c FLOAT min coverage [${opt.min_cov}]`);
150
- print(` -d FLOAT max divergence [${opt.max_dv}]`);
151
- print(` -e FLOAT max difference [${opt.max_diff}]`);
152
- return;
153
- }
154
-
155
- // read
156
- let a = [], len = {}, name2len = {};
157
- for (const line of k8_readline(args[0])) {
158
- let m, t = line.split("\t");
159
- if (t[4] != "+") continue;
160
- for (let i = 1; i < 4; ++i) t[i] = parseInt(t[i]);
161
- for (let i = 6; i < 11; ++i) t[i] = parseInt(t[i]);
162
- const len1 = t[1], len2 = t[6];
163
- let s1 = -1, dv = -1.0;
164
- for (let i = 12; i < t.length; ++i) {
165
- if ((m = /^(s1|dv):\S:(\S+)/.exec(t[i])) != null) {
166
- if (m[1] == "s1") s1 = parseInt(m[2]);
167
- else if (m[1] == "dv") dv = parseFloat(m[2]);
168
- }
169
- }
170
- if (s1 < 0 || dv < 0) continue;
171
- const cov1 = (parseInt(t[3]) - parseInt(t[2])) / len1;
172
- const cov2 = (parseInt(t[8]) - parseInt(t[7])) / len2;
173
- const min_cov = cov1 < cov2? cov1 : cov2;
174
- const max_cov = cov1 > cov2? cov1 : cov2;
175
- name2len[t[0]] = len1;
176
- name2len[t[5]] = len2;
177
- a.push({ name1:t[0], name2:t[5], len1:len1, len2:len2, min_cov:min_cov, max_cov:max_cov, s1:s1, dv:dv, cov1:cov1, cov2:cov2, st1:t[2], en1:t[3], st2:t[7], en2:t[8], blen:t[10] });
178
- len[t[0]] = len1, len[t[5]] = len2;
179
- }
180
- warn(`Read ${a.length} hits`);
181
-
182
- // merge duplicated hits
183
- let h = {};
184
- for (let i = 0; i < a.length; ++i) {
185
- const key = `${a[i].name1}\t${a[i].name2}`;
186
- if (h[key] == null) h[key] = [];
187
- h[key].push(a[i]);
188
- }
189
- a = [];
190
- for (const key in h)
191
- a.push(merge_hits(h[key]));
192
-
193
- // core loop
194
- while (a.length > 1) {
195
- // select the sequence with the highest sum of s1
196
- let h = {};
197
- for (let i = 0; i < a.length; ++i) {
198
- if (h[a[i].name1] == null) h[a[i].name1] = 0;
199
- h[a[i].name1] += a[i].s1;
200
- }
201
- let max_s1 = 0, max_name = "";
202
- for (const name in h)
203
- if (max_s1 < h[name])
204
- max_s1 = h[name], max_name = name;
205
- // find contigs in the same group
206
- h = {};
207
- h[max_name] = 1;
208
- for (let i = 0; i < a.length; ++i) {
209
- if (a[i].name1 != max_name && a[i].name2 != max_name)
210
- continue;
211
- const diff1 = a[i].len1 * (1.0 - a[i].cov1);
212
- const diff2 = a[i].len2 * (1.0 - a[i].cov2);
213
- if (a[i].min_cov >= opt.min_cov && a[i].dv <= opt.max_dv && diff1 <= opt.max_diff && diff2 <= opt.max_diff)
214
- h[a[i].name1] = h[a[i].name2] = 1;
215
- }
216
- let n = 0;
217
- for (const key in h) {
218
- ++n;
219
- delete name2len[key];
220
- }
221
- print(`SD\t${max_name}\t${n}`);
222
- for (const key in h) print(`CL\t${key}\t${len[key]}`);
223
- print("//");
224
- // filter out redundant hits
225
- let b = [];
226
- for (let i = 0; i < a.length; ++i)
227
- if (h[a[i].name1] == null && h[a[i].name2] == null)
228
- b.push(a[i]);
229
- warn(`Reduced the number of hits from ${a.length} to ${b.length}`);
230
- a = b;
231
- }
232
-
233
- // output remaining singletons
234
- for (const key in name2len) {
235
- print(`SD\t${key}\t1`);
236
- print(`CL\t${key}\t${name2len[key]}`);
237
- print(`//`);
238
- }
239
- }
240
-
241
- main(arguments);