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.
- checksums.yaml +4 -4
- data/README.md +48 -63
- data/ext/minimap2/Makefile +1 -1
- data/ext/minimap2/format.c +12 -2
- data/ext/minimap2/hit.c +19 -8
- data/ext/minimap2/ksw2_ll_sse.c +2 -2
- data/ext/minimap2/minimap.h +2 -1
- data/ext/minimap2/pe.c +7 -2
- data/ext/ruby_minimap2/extconf.rb +47 -0
- data/ext/ruby_minimap2/native_main.c +15 -0
- data/ext/ruby_minimap2/ruby_minimap2.c +1134 -0
- data/lib/minimap2/aligner.rb +66 -374
- data/lib/minimap2/alignment.rb +22 -11
- data/lib/minimap2/version.rb +2 -1
- data/lib/minimap2.rb +39 -110
- metadata +8 -89
- data/ext/Rakefile +0 -60
- data/ext/cmappy/cmappy.c +0 -134
- data/ext/cmappy/cmappy.h +0 -46
- data/ext/minimap2/FAQ.md +0 -46
- data/ext/minimap2/MANIFEST.in +0 -10
- data/ext/minimap2/Makefile.simde +0 -97
- data/ext/minimap2/NEWS.md +0 -989
- data/ext/minimap2/README.md +0 -428
- data/ext/minimap2/code_of_conduct.md +0 -30
- data/ext/minimap2/cookbook.md +0 -243
- data/ext/minimap2/minimap2.1 +0 -844
- data/ext/minimap2/misc/README.md +0 -180
- data/ext/minimap2/misc/pafcluster.js +0 -241
- data/ext/minimap2/misc/paftools.js +0 -3734
- data/ext/minimap2/pyproject.toml +0 -2
- data/ext/minimap2/python/README.rst +0 -198
- data/ext/minimap2/python/cmappy.h +0 -152
- data/ext/minimap2/python/cmappy.pxd +0 -156
- data/ext/minimap2/python/mappy.pyx +0 -289
- data/ext/minimap2/python/minimap2.py +0 -41
- data/ext/minimap2/setup.py +0 -55
- data/ext/minimap2/test/MT-human.fa +0 -278
- data/ext/minimap2/test/MT-orang.fa +0 -276
- data/ext/minimap2/test/q-inv.fa +0 -4
- data/ext/minimap2/test/q2.fa +0 -2
- data/ext/minimap2/test/t-inv.fa +0 -127
- data/ext/minimap2/test/t2.fa +0 -2
- data/ext/minimap2/test/x3s-aln.txt +0 -5
- data/ext/minimap2/test/x3s-qry.fa +0 -5
- data/ext/minimap2/test/x3s-ref.fa +0 -10
- data/ext/minimap2/tex/Makefile +0 -21
- data/ext/minimap2/tex/bioinfo.cls +0 -930
- data/ext/minimap2/tex/blasr-mc.eval +0 -17
- data/ext/minimap2/tex/bowtie2-s3.sam.eval +0 -28
- data/ext/minimap2/tex/bwa-s3.sam.eval +0 -52
- data/ext/minimap2/tex/bwa.eval +0 -55
- data/ext/minimap2/tex/eval2roc.pl +0 -33
- data/ext/minimap2/tex/graphmap.eval +0 -4
- data/ext/minimap2/tex/hs38-simu.sh +0 -10
- data/ext/minimap2/tex/minialign.eval +0 -49
- data/ext/minimap2/tex/minimap2.bib +0 -460
- data/ext/minimap2/tex/minimap2.tex +0 -724
- data/ext/minimap2/tex/mm2-s3.sam.eval +0 -62
- data/ext/minimap2/tex/mm2-update.tex +0 -240
- data/ext/minimap2/tex/mm2.approx.eval +0 -12
- data/ext/minimap2/tex/mm2.eval +0 -13
- data/ext/minimap2/tex/natbib.bst +0 -1288
- data/ext/minimap2/tex/natbib.sty +0 -803
- data/ext/minimap2/tex/ngmlr.eval +0 -38
- data/ext/minimap2/tex/roc.gp +0 -60
- data/ext/minimap2/tex/snap-s3.sam.eval +0 -62
- data/ext/minimap2.patch +0 -19
- data/lib/minimap2/ffi/constants.rb +0 -267
- data/lib/minimap2/ffi/functions.rb +0 -239
- data/lib/minimap2/ffi/mappy.rb +0 -104
- data/lib/minimap2/ffi.rb +0 -27
data/lib/minimap2/aligner.rb
CHANGED
|
@@ -1,380 +1,72 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Minimap2
|
|
4
|
+
# Builds or loads a minimap2 index and maps sequences against it.
|
|
5
|
+
#
|
|
6
|
+
# Calls on the same Aligner are thread-safe and serialized. Different Aligner
|
|
7
|
+
# instances can map concurrently.
|
|
8
|
+
#
|
|
9
|
+
# @!method initialize(path = nil, seq: nil, preset: nil, k: nil, w: nil, min_cnt: nil, min_chain_score: nil, min_dp_score: nil, bw: nil, bw_long: nil, best_n: nil, n_threads: 3, fn_idx_out: nil, max_frag_len: nil, extra_flags: nil, scoring: nil, sc_ambi: nil, max_chain_skip: nil, batch_size: nil)
|
|
10
|
+
# Creates an aligner from a FASTA/FASTQ/index file or one in-memory sequence.
|
|
11
|
+
# @param path [String, nil] sequence or index file
|
|
12
|
+
# @param seq [String, nil] single sequence to index when path is nil
|
|
13
|
+
# @param preset [String, Symbol, nil] minimap2 preset such as map-ont, map-pb, map-hifi, sr, splice, or asm5
|
|
14
|
+
# @param k [Integer, nil] k-mer length in the range 1..28
|
|
15
|
+
# @param w [Integer, nil] minimizer window size in the range 1..255
|
|
16
|
+
# @param min_cnt [Integer, nil] minimum number of minimizers on a chain
|
|
17
|
+
# @param min_chain_score [Integer, nil] minimum chaining score
|
|
18
|
+
# @param min_dp_score [Integer, nil] minimum DP alignment score
|
|
19
|
+
# @param bw [Integer, nil] chaining and alignment bandwidth
|
|
20
|
+
# @param bw_long [Integer, nil] bandwidth for long-gap rechaining
|
|
21
|
+
# @param best_n [Integer, nil] maximum number of alignments to return
|
|
22
|
+
# @param n_threads [Integer] number of indexing threads
|
|
23
|
+
# @param fn_idx_out [String, nil] path at which to write the generated index
|
|
24
|
+
# @param max_frag_len [Integer, nil] maximum fragment length
|
|
25
|
+
# @param extra_flags [Integer, nil] additional minimap2 mapping flags
|
|
26
|
+
# @param scoring [Array<Integer>, nil] four, six, or seven scoring values
|
|
27
|
+
# @param sc_ambi [Integer, nil] score for ambiguous bases
|
|
28
|
+
# @param max_chain_skip [Integer, nil] maximum chain-skip count
|
|
29
|
+
# @param batch_size [Integer, nil] index batch size; small values create a multipart index
|
|
30
|
+
# @raise [ArgumentError] if a preset, k, or w is invalid
|
|
31
|
+
# @raise [Minimap2::Error] if the index cannot be initialized or lacks sequence data
|
|
32
|
+
#
|
|
33
|
+
# @!method align(seq, seq2 = nil, name: nil, cs: false, ds: false, md: false, max_frag_len: nil, extra_flags: nil)
|
|
34
|
+
# Maps one sequence or a paired sequence.
|
|
35
|
+
# @param seq [String] query sequence
|
|
36
|
+
# @param seq2 [String, nil] paired query sequence
|
|
37
|
+
# @param name [String, nil] query name stored in Alignment; defaults to "*"
|
|
38
|
+
# @param cs [Boolean] generate the cs tag
|
|
39
|
+
# @param ds [Boolean] generate the ds tag
|
|
40
|
+
# @param md [Boolean] generate the MD tag
|
|
41
|
+
# @param max_frag_len [Integer, nil] per-call maximum fragment length
|
|
42
|
+
# @param extra_flags [Integer, nil] per-call additional mapping flags
|
|
43
|
+
# @return [Array<Alignment>] alignments, or an empty array when no index or hit is available
|
|
44
|
+
#
|
|
45
|
+
# @!method seq(name, start = 0, stop = 0x7fffffff)
|
|
46
|
+
# Retrieves a subsequence from the index. By default, reads to the end of the sequence.
|
|
47
|
+
# @return [String, nil] an ASCII-8BIT sequence, or nil if unavailable
|
|
48
|
+
#
|
|
49
|
+
# @!method k
|
|
50
|
+
# @return [Integer] minimizer k-mer length
|
|
51
|
+
# @raise [Minimap2::Error] if no index is available
|
|
52
|
+
#
|
|
53
|
+
# @!method w
|
|
54
|
+
# @return [Integer] minimizer window size
|
|
55
|
+
# @raise [Minimap2::Error] if no index is available
|
|
56
|
+
#
|
|
57
|
+
# @!method n_seq
|
|
58
|
+
# @return [Integer] number of sequences across all index parts
|
|
59
|
+
#
|
|
60
|
+
# @!method seq_names
|
|
61
|
+
# Returns names in index order, including duplicate names.
|
|
62
|
+
# @return [Array<String>] UTF-8 sequence names
|
|
63
|
+
#
|
|
64
|
+
# @!method index?
|
|
65
|
+
# @return [Boolean] whether a live index is available
|
|
66
|
+
#
|
|
67
|
+
# @!method free_index
|
|
68
|
+
# Releases every native index owned by this object. Calling it repeatedly is safe.
|
|
69
|
+
# @return [nil]
|
|
4
70
|
class Aligner
|
|
5
|
-
attr_reader :idx_opt, :map_opt, :index
|
|
6
|
-
|
|
7
|
-
# Create a new aligner.
|
|
8
|
-
#
|
|
9
|
-
# @param fn_idx_in [String] index or sequence file name.
|
|
10
|
-
# @param seq [String] a single sequence to index.
|
|
11
|
-
# @param preset [String] minimap2 preset.
|
|
12
|
-
# * map-pb : PacBio CLR genomic reads
|
|
13
|
-
# * map-ont : Oxford Nanopore genomic reads
|
|
14
|
-
# * map-hifi : PacBio HiFi/CCS genomic reads (v2.19 or later)
|
|
15
|
-
# * asm20 : PacBio HiFi/CCS genomic reads (v2.18 or earlier)
|
|
16
|
-
# * sr : short genomic paired-end reads
|
|
17
|
-
# * splice : spliced long reads (strand unknown)
|
|
18
|
-
# * splice:hq : Final PacBio Iso-seq or traditional cDNA
|
|
19
|
-
# * asm5 : intra-species asm-to-asm alignment
|
|
20
|
-
# * ava-pb : PacBio read overlap
|
|
21
|
-
# * ava-ont : Nanopore read overlap
|
|
22
|
-
# @param k [Integer] k-mer length, no larger than 28.
|
|
23
|
-
# @param w [Integer] minimizer window size, no larger than 255.
|
|
24
|
-
# @param min_cnt [Integer] minimum number of minimizers on a chain.
|
|
25
|
-
# @param min_chain_score [Integer] minimum chain score.
|
|
26
|
-
# @param min_dp_score
|
|
27
|
-
# @param bw [Integer] chaining and alignment band width. (initial chaining and extension)
|
|
28
|
-
# @param bw_long [Integer] chaining and alignment band width (RMQ-based rechaining and closing gaps)
|
|
29
|
-
# @param best_n [Integer] max number of alignments to return.
|
|
30
|
-
# @param n_threads [Integer] number of indexing threads.
|
|
31
|
-
# @param fn_idx_out [String] name of file to which the index is written.
|
|
32
|
-
# This parameter has no effect if seq is set.
|
|
33
|
-
# @param max_frag_len [Integer]
|
|
34
|
-
# @param extra_flags [Integer] additional flags defined in minimap.h.
|
|
35
|
-
# @param scoring [Array] scoring system.
|
|
36
|
-
# It is a tuple/list consisting of 4, 6 or 7 positive integers.
|
|
37
|
-
# The first 4 elements specify match scoring, mismatch penalty, gap open and gap extension penalty.
|
|
38
|
-
# The 5th and 6th elements, if present, set long-gap open and long-gap extension penalty.
|
|
39
|
-
# The 7th sets a mismatch penalty involving ambiguous bases.
|
|
40
|
-
|
|
41
|
-
def initialize(
|
|
42
|
-
fn_idx_in = nil,
|
|
43
|
-
seq: nil,
|
|
44
|
-
preset: nil,
|
|
45
|
-
k: nil,
|
|
46
|
-
w: nil,
|
|
47
|
-
min_cnt: nil,
|
|
48
|
-
min_chain_score: nil,
|
|
49
|
-
min_dp_score: nil,
|
|
50
|
-
bw: nil,
|
|
51
|
-
bw_long: nil,
|
|
52
|
-
best_n: nil,
|
|
53
|
-
n_threads: 3,
|
|
54
|
-
fn_idx_out: nil,
|
|
55
|
-
max_frag_len: nil,
|
|
56
|
-
extra_flags: nil,
|
|
57
|
-
scoring: nil,
|
|
58
|
-
sc_ambi: nil,
|
|
59
|
-
max_chain_skip: nil,
|
|
60
|
-
batch_size: nil
|
|
61
|
-
)
|
|
62
|
-
@idx_opt = FFI::IdxOpt.new
|
|
63
|
-
@map_opt = FFI::MapOpt.new
|
|
64
|
-
|
|
65
|
-
r = FFI.mm_set_opt(preset, idx_opt, map_opt)
|
|
66
|
-
raise ArgumentError, "Unknown preset name: #{preset}" if r == -1
|
|
67
|
-
|
|
68
|
-
# always perform alignment
|
|
69
|
-
map_opt[:flag] |= 4
|
|
70
|
-
|
|
71
|
-
# Keep a large batch_size by default (mappy-compatible behavior) to avoid
|
|
72
|
-
# splitting indexes unless explicitly requested.
|
|
73
|
-
idx_opt[:batch_size] = 0x7fffffffffffffff
|
|
74
|
-
idx_opt[:batch_size] = batch_size if batch_size
|
|
75
|
-
|
|
76
|
-
# override preset options
|
|
77
|
-
idx_opt[:k] = k if k
|
|
78
|
-
idx_opt[:w] = w if w
|
|
79
|
-
map_opt[:min_cnt] = min_cnt if min_cnt
|
|
80
|
-
map_opt[:min_chain_score] = min_chain_score if min_chain_score
|
|
81
|
-
map_opt[:min_dp_max] = min_dp_score if min_dp_score
|
|
82
|
-
map_opt[:bw] = bw if bw
|
|
83
|
-
map_opt[:bw_long] = bw_long if bw_long
|
|
84
|
-
map_opt[:best_n] = best_n if best_n
|
|
85
|
-
map_opt[:max_frag_len] = max_frag_len if max_frag_len
|
|
86
|
-
map_opt[:flag] |= extra_flags if extra_flags
|
|
87
|
-
if scoring && scoring.size >= 4
|
|
88
|
-
map_opt[:a] = scoring[0]
|
|
89
|
-
map_opt[:b] = scoring[1]
|
|
90
|
-
map_opt[:q] = scoring[2]
|
|
91
|
-
map_opt[:e] = scoring[3]
|
|
92
|
-
map_opt[:q2] = map_opt[:q]
|
|
93
|
-
map_opt[:e2] = map_opt[:e]
|
|
94
|
-
if scoring.size >= 6
|
|
95
|
-
map_opt[:q2] = scoring[4]
|
|
96
|
-
map_opt[:e2] = scoring[5]
|
|
97
|
-
map_opt[:sc_ambi] = scoring[6] if scoring.size >= 7
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
map_opt[:sc_ambi] = sc_ambi if sc_ambi
|
|
101
|
-
map_opt[:max_chain_skip] = max_chain_skip if max_chain_skip
|
|
102
|
-
|
|
103
|
-
if fn_idx_in
|
|
104
|
-
warn "Since fn_idx_in is specified, the seq argument will be ignored." if seq
|
|
105
|
-
reader = FFI.mm_idx_reader_open(fn_idx_in, idx_opt, fn_idx_out)
|
|
106
|
-
|
|
107
|
-
# The Ruby version raises an error here
|
|
108
|
-
raise "Cannot open : #{fn_idx_in}" if reader.null?
|
|
109
|
-
|
|
110
|
-
@indexes = []
|
|
111
|
-
begin
|
|
112
|
-
loop do
|
|
113
|
-
idx = FFI.mm_idx_reader_read(reader, n_threads)
|
|
114
|
-
break if idx.nil? || idx.null?
|
|
115
|
-
|
|
116
|
-
# Initialize sequence name index for each part
|
|
117
|
-
FFI.mm_idx_index_name(idx)
|
|
118
|
-
@indexes << idx
|
|
119
|
-
end
|
|
120
|
-
ensure
|
|
121
|
-
FFI.mm_idx_reader_close(reader)
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
raise "Failed to read index parts from: #{fn_idx_in}" if @indexes.empty?
|
|
125
|
-
|
|
126
|
-
# Keep backward-compatible accessor for a single index
|
|
127
|
-
@index = @indexes[0]
|
|
128
|
-
FFI.mm_mapopt_update(map_opt, index)
|
|
129
|
-
elsif seq
|
|
130
|
-
@index = FFI.mappy_idx_seq(
|
|
131
|
-
idx_opt[:w], idx_opt[:k], idx_opt[:flag] & 1,
|
|
132
|
-
idx_opt[:bucket_bits], seq, seq.size
|
|
133
|
-
)
|
|
134
|
-
@indexes = [@index]
|
|
135
|
-
FFI.mm_mapopt_update(map_opt, index)
|
|
136
|
-
map_opt[:mid_occ] = 1000 # don't filter high-occ seeds
|
|
137
|
-
else
|
|
138
|
-
@indexes = []
|
|
139
|
-
@index = FFI::Idx.new(::FFI::Pointer::NULL)
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# Explicitly releases the memory of the index object.
|
|
144
|
-
|
|
145
|
-
def free_index
|
|
146
|
-
indexes = @indexes
|
|
147
|
-
if indexes && !indexes.empty?
|
|
148
|
-
indexes.each do |idx|
|
|
149
|
-
FFI.mm_idx_destroy(idx) unless idx.nil? || idx.null?
|
|
150
|
-
end
|
|
151
|
-
elsif defined?(@index) && !@index.nil? && !@index.null?
|
|
152
|
-
FFI.mm_idx_destroy(@index)
|
|
153
|
-
end
|
|
154
|
-
ensure
|
|
155
|
-
@indexes = []
|
|
156
|
-
@index = FFI::Idx.new(::FFI::Pointer::NULL)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# @param seq [String]
|
|
160
|
-
# @param seq2 [String]
|
|
161
|
-
# @param buf [FFI::TBuf]
|
|
162
|
-
# @param cs [true, false]
|
|
163
|
-
# @param md [true, false]
|
|
164
|
-
# @param max_frag_len [Integer]
|
|
165
|
-
# @param extra_flags [Integer]
|
|
166
|
-
# @note Name change: map -> align
|
|
167
|
-
# In the Ruby language, the name map means iterator.
|
|
168
|
-
# The original name is map, but here I use the method name align.
|
|
169
|
-
# @note The use of Enumerator is being considered. The method names may change again.
|
|
170
|
-
# @return [Array] alignments
|
|
171
|
-
|
|
172
|
-
def align(
|
|
173
|
-
seq, seq2 = nil,
|
|
174
|
-
name: nil,
|
|
175
|
-
buf: nil,
|
|
176
|
-
cs: false,
|
|
177
|
-
md: false,
|
|
178
|
-
max_frag_len: nil,
|
|
179
|
-
extra_flags: nil
|
|
180
|
-
)
|
|
181
|
-
return if index.null?
|
|
182
|
-
return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
|
|
183
|
-
|
|
184
|
-
orig_map_opt_bytes = map_opt.to_ptr.read_bytes(FFI::MapOpt.size)
|
|
185
|
-
orig_best_n = map_opt[:best_n]
|
|
186
|
-
|
|
187
|
-
owned_buf = false
|
|
188
|
-
if buf.nil?
|
|
189
|
-
buf = FFI.mm_tbuf_init
|
|
190
|
-
owned_buf = true
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
km = FFI.mm_tbuf_get_km(buf)
|
|
194
|
-
alignments = []
|
|
195
|
-
|
|
196
|
-
idx_parts = @indexes
|
|
197
|
-
idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
|
|
198
|
-
|
|
199
|
-
begin
|
|
200
|
-
idx_parts.each do |idx_part|
|
|
201
|
-
next if idx_part.nil? || idx_part.null?
|
|
202
|
-
|
|
203
|
-
# Update options for this specific index part
|
|
204
|
-
FFI.mm_mapopt_update(map_opt, idx_part)
|
|
205
|
-
|
|
206
|
-
# Per-call options (do not leak across calls)
|
|
207
|
-
map_opt[:flag] |= 4
|
|
208
|
-
map_opt[:best_n] = orig_best_n
|
|
209
|
-
map_opt[:max_frag_len] = max_frag_len if max_frag_len
|
|
210
|
-
map_opt[:flag] |= extra_flags if extra_flags
|
|
211
|
-
|
|
212
|
-
n_regs_ptr = ::FFI::MemoryPointer.new :int
|
|
213
|
-
regs_ptr = FFI.mm_map_aux(idx_part, name, seq, seq2, n_regs_ptr, buf, map_opt)
|
|
214
|
-
n_regs = n_regs_ptr.read_int
|
|
215
|
-
|
|
216
|
-
next if regs_ptr.nil? || regs_ptr.null? || n_regs <= 0
|
|
217
|
-
|
|
218
|
-
regs = Array.new(n_regs) do |i|
|
|
219
|
-
FFI::Reg1.new(regs_ptr + i * FFI::Reg1.size)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
hit = FFI::Hit.new
|
|
223
|
-
|
|
224
|
-
cs_buf_ptr = nil
|
|
225
|
-
m_cs_ptr = nil
|
|
226
|
-
if cs || md
|
|
227
|
-
cs_buf_ptr = ::FFI::MemoryPointer.new(:pointer)
|
|
228
|
-
cs_buf_ptr.write_pointer(::FFI::Pointer::NULL)
|
|
229
|
-
m_cs_ptr = ::FFI::MemoryPointer.new(:int)
|
|
230
|
-
m_cs_ptr.write_int(0)
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
i = 0
|
|
234
|
-
begin
|
|
235
|
-
while i < n_regs
|
|
236
|
-
FFI.mm_reg2hitpy(idx_part, regs[i], hit)
|
|
237
|
-
|
|
238
|
-
c = hit[:cigar32].read_array_of_uint32(hit[:n_cigar32])
|
|
239
|
-
cigar = c.map { |x| [x >> 4, x & 0xf] } # 32-bit CIGAR encoding -> Ruby array
|
|
240
|
-
|
|
241
|
-
_cs = ""
|
|
242
|
-
_md = ""
|
|
243
|
-
if cs or md
|
|
244
|
-
cur_seq = hit[:seg_id] > 0 && seq2 ? seq2 : seq
|
|
245
|
-
|
|
246
|
-
if cs
|
|
247
|
-
l_cs_str = FFI.mm_gen_cs(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq, 1)
|
|
248
|
-
cs_ptr = cs_buf_ptr.read_pointer
|
|
249
|
-
_cs = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
if md
|
|
253
|
-
l_cs_str = FFI.mm_gen_md(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq)
|
|
254
|
-
cs_ptr = cs_buf_ptr.read_pointer
|
|
255
|
-
_md = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
alignments << Alignment.new(hit, cigar, _cs, _md)
|
|
260
|
-
|
|
261
|
-
FFI.mm_free_reg1(regs[i])
|
|
262
|
-
i += 1
|
|
263
|
-
end
|
|
264
|
-
ensure
|
|
265
|
-
while i < n_regs
|
|
266
|
-
FFI.mm_free_reg1(regs[i])
|
|
267
|
-
i += 1
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
if cs_buf_ptr
|
|
271
|
-
cs_ptr = cs_buf_ptr.read_pointer
|
|
272
|
-
FFI.mappy_free(cs_ptr) unless cs_ptr.nil? || cs_ptr.null?
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
# Free the mm_map/mm_map_aux return value array itself
|
|
276
|
-
FFI.mappy_free(regs_ptr) unless regs_ptr.nil? || regs_ptr.null?
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
ensure
|
|
280
|
-
FFI.mm_tbuf_destroy(buf) if owned_buf
|
|
281
|
-
|
|
282
|
-
# Restore map_opt to the state before this call
|
|
283
|
-
map_opt.to_ptr.put_bytes(0, orig_map_opt_bytes)
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
if orig_best_n && orig_best_n > 0 && alignments.length > orig_best_n
|
|
287
|
-
alignments.sort_by! do |aln|
|
|
288
|
-
[
|
|
289
|
-
aln.primary? ? 1 : 0,
|
|
290
|
-
aln.mapq,
|
|
291
|
-
aln.mlen,
|
|
292
|
-
aln.blen,
|
|
293
|
-
-aln.nm
|
|
294
|
-
]
|
|
295
|
-
end
|
|
296
|
-
alignments.reverse!
|
|
297
|
-
alignments = alignments.take(orig_best_n)
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
alignments
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
# Retrieve a subsequence from the index.
|
|
304
|
-
# @param name
|
|
305
|
-
# @param start
|
|
306
|
-
# @param stop
|
|
307
|
-
|
|
308
|
-
def seq(name, start = 0, stop = 0x7fffffff)
|
|
309
|
-
return if index.null?
|
|
310
|
-
return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
|
|
311
|
-
|
|
312
|
-
idx_parts = @indexes
|
|
313
|
-
idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
|
|
314
|
-
|
|
315
|
-
idx_parts.each do |idx_part|
|
|
316
|
-
next if idx_part.nil? || idx_part.null?
|
|
317
|
-
|
|
318
|
-
lp = ::FFI::MemoryPointer.new(:int)
|
|
319
|
-
s = FFI.mappy_fetch_seq(idx_part, name, start, stop, lp)
|
|
320
|
-
l = lp.read_int
|
|
321
|
-
if l == 0
|
|
322
|
-
FFI.mappy_free(s) unless s.nil? || s.null?
|
|
323
|
-
next
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
begin
|
|
327
|
-
return s.read_string(l)
|
|
328
|
-
ensure
|
|
329
|
-
FFI.mappy_free(s) unless s.nil? || s.null?
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
nil
|
|
334
|
-
end
|
|
335
|
-
|
|
336
|
-
# k-mer length, no larger than 28
|
|
337
|
-
|
|
338
|
-
def k
|
|
339
|
-
index[:k]
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
# minimizer window size, no larger than 255
|
|
343
|
-
|
|
344
|
-
def w
|
|
345
|
-
index[:w]
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
def n_seq
|
|
349
|
-
return 0 if index.null?
|
|
350
|
-
|
|
351
|
-
indexes = @indexes
|
|
352
|
-
return index[:n_seq] if indexes.nil? || indexes.empty?
|
|
353
|
-
|
|
354
|
-
indexes.sum { |idx| idx.nil? || idx.null? ? 0 : idx[:n_seq] }
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
def seq_names
|
|
358
|
-
return [] if index.null?
|
|
359
|
-
|
|
360
|
-
indexes = @indexes
|
|
361
|
-
indexes = [index] if indexes.nil? || indexes.empty?
|
|
362
|
-
|
|
363
|
-
names = []
|
|
364
|
-
seen = {}
|
|
365
|
-
indexes.each do |idx|
|
|
366
|
-
next if idx.nil? || idx.null?
|
|
367
|
-
|
|
368
|
-
ptr = idx[:seq].to_ptr
|
|
369
|
-
idx[:n_seq].times do |i|
|
|
370
|
-
name = FFI::IdxSeq.new(ptr + i * FFI::IdxSeq.size)[:name]
|
|
371
|
-
next if seen[name]
|
|
372
|
-
|
|
373
|
-
seen[name] = true
|
|
374
|
-
names << name
|
|
375
|
-
end
|
|
376
|
-
end
|
|
377
|
-
names
|
|
378
|
-
end
|
|
379
71
|
end
|
|
380
72
|
end
|
data/lib/minimap2/alignment.rb
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
module Minimap2
|
|
4
4
|
# Alignment result.
|
|
5
5
|
#
|
|
6
|
+
# @!attribute qname
|
|
7
|
+
# @return [String] query sequence name.
|
|
8
|
+
# @!attribute qlen
|
|
9
|
+
# @return [Integer] query sequence length.
|
|
6
10
|
# @!attribute ctg
|
|
7
11
|
# @return [String] name of the reference sequence the query is mapped to.
|
|
8
12
|
# @!attribute ctg_len
|
|
@@ -39,22 +43,27 @@ module Minimap2
|
|
|
39
43
|
# @return [Integer] read number that the alignment corresponds to;
|
|
40
44
|
# 1 for the first read and 2 for the second read.
|
|
41
45
|
# @!attribute cs
|
|
42
|
-
# @return [String] the cs tag.
|
|
46
|
+
# @return [String, nil] the cs tag.
|
|
47
|
+
# @!attribute ds
|
|
48
|
+
# @return [String, nil] the ds tag.
|
|
43
49
|
# @!attribute md
|
|
44
|
-
# @return [String] the MD tag as in the SAM format.
|
|
45
|
-
# It is an empty string unless the md argument is applied when calling Aligner#align.
|
|
50
|
+
# @return [String, nil] the MD tag as in the SAM format.
|
|
46
51
|
# @!attribute cigar_str
|
|
47
52
|
# @return [String] CIGAR string.
|
|
48
53
|
|
|
49
54
|
class Alignment
|
|
55
|
+
CIGAR_STR = "MIDNSHP=XB"
|
|
56
|
+
|
|
50
57
|
def self.keys
|
|
51
|
-
%i[ctg ctg_len r_st r_en strand trans_strand blen mlen nm primary
|
|
52
|
-
q_st q_en mapq cigar read_num cs md cigar_str]
|
|
58
|
+
%i[qname qlen ctg ctg_len r_st r_en strand trans_strand blen mlen nm primary
|
|
59
|
+
q_st q_en mapq cigar read_num cs ds md cigar_str]
|
|
53
60
|
end
|
|
54
61
|
|
|
55
62
|
attr_reader(*keys)
|
|
56
63
|
|
|
57
|
-
def initialize(h, cigar, cs = nil, md = nil)
|
|
64
|
+
def initialize(h, cigar, cs = nil, ds = nil, md = nil)
|
|
65
|
+
@qname = h[:qname]
|
|
66
|
+
@qlen = h[:qlen]
|
|
58
67
|
@ctg = h[:ctg]
|
|
59
68
|
@ctg_len = h[:ctg_len]
|
|
60
69
|
@r_st = h[:ctg_start]
|
|
@@ -71,9 +80,10 @@ module Minimap2
|
|
|
71
80
|
@cigar = cigar
|
|
72
81
|
@read_num = h[:seg_id] + 1
|
|
73
82
|
@cs = cs
|
|
83
|
+
@ds = ds
|
|
74
84
|
@md = md
|
|
75
85
|
|
|
76
|
-
@cigar_str = cigar.map { |x| x[0].to_s +
|
|
86
|
+
@cigar_str = cigar.map { |x| x[0].to_s + CIGAR_STR[x[1]] }.join
|
|
77
87
|
end
|
|
78
88
|
|
|
79
89
|
def primary?
|
|
@@ -86,7 +96,7 @@ module Minimap2
|
|
|
86
96
|
self.class.keys.map { |k| [k, __send__(k)] }.to_h
|
|
87
97
|
end
|
|
88
98
|
|
|
89
|
-
# Convert to the PAF format
|
|
99
|
+
# Convert to the PAF format.
|
|
90
100
|
|
|
91
101
|
def to_s
|
|
92
102
|
strand = if @strand > 0
|
|
@@ -104,10 +114,11 @@ module Minimap2
|
|
|
104
114
|
else
|
|
105
115
|
"ts:A:."
|
|
106
116
|
end
|
|
107
|
-
a = [@q_st, @q_en, strand, @ctg, @ctg_len, @r_st, @r_en,
|
|
117
|
+
a = [@qname, @qlen, @q_st, @q_en, strand, @ctg, @ctg_len, @r_st, @r_en,
|
|
108
118
|
@mlen, @blen, @mapq, tp, ts, "cg:Z:#{@cigar_str}"]
|
|
109
|
-
a << "cs:Z:#{@cs}"
|
|
110
|
-
a << "
|
|
119
|
+
a << "cs:Z:#{@cs}" unless @cs.nil? || @cs.empty?
|
|
120
|
+
a << "ds:Z:#{@ds}" unless @ds.nil? || @ds.empty?
|
|
121
|
+
a << "MD:Z:#{@md}" unless @md.nil? || @md.empty?
|
|
111
122
|
a.join("\t")
|
|
112
123
|
end
|
|
113
124
|
end
|