minimap2 0.2.31.0 → 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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +47 -64
  3. data/ext/ruby_minimap2/extconf.rb +47 -0
  4. data/ext/ruby_minimap2/native_main.c +15 -0
  5. data/ext/ruby_minimap2/ruby_minimap2.c +1134 -0
  6. data/lib/minimap2/aligner.rb +66 -383
  7. data/lib/minimap2/alignment.rb +15 -8
  8. data/lib/minimap2/version.rb +2 -1
  9. data/lib/minimap2.rb +39 -110
  10. metadata +8 -89
  11. data/ext/Rakefile +0 -63
  12. data/ext/cmappy/cmappy.c +0 -134
  13. data/ext/cmappy/cmappy.h +0 -46
  14. data/ext/minimap2/FAQ.md +0 -46
  15. data/ext/minimap2/MANIFEST.in +0 -10
  16. data/ext/minimap2/Makefile.simde +0 -97
  17. data/ext/minimap2/NEWS.md +0 -1022
  18. data/ext/minimap2/README.md +0 -429
  19. data/ext/minimap2/code_of_conduct.md +0 -30
  20. data/ext/minimap2/cookbook.md +0 -243
  21. data/ext/minimap2/minimap2.1 +0 -844
  22. data/ext/minimap2/misc/README.md +0 -180
  23. data/ext/minimap2/misc/pafcluster.js +0 -241
  24. data/ext/minimap2/misc/paftools.js +0 -3830
  25. data/ext/minimap2/pyproject.toml +0 -2
  26. data/ext/minimap2/python/README.rst +0 -198
  27. data/ext/minimap2/python/cmappy.h +0 -152
  28. data/ext/minimap2/python/cmappy.pxd +0 -157
  29. data/ext/minimap2/python/mappy.pyx +0 -297
  30. data/ext/minimap2/python/minimap2.py +0 -43
  31. data/ext/minimap2/setup.py +0 -55
  32. data/ext/minimap2/test/MT-human.fa +0 -278
  33. data/ext/minimap2/test/MT-orang.fa +0 -276
  34. data/ext/minimap2/test/q-inv.fa +0 -4
  35. data/ext/minimap2/test/q2.fa +0 -2
  36. data/ext/minimap2/test/t-inv.fa +0 -127
  37. data/ext/minimap2/test/t2.fa +0 -2
  38. data/ext/minimap2/test/x3s-aln.txt +0 -5
  39. data/ext/minimap2/test/x3s-qry.fa +0 -5
  40. data/ext/minimap2/test/x3s-ref.fa +0 -10
  41. data/ext/minimap2/tex/Makefile +0 -21
  42. data/ext/minimap2/tex/bioinfo.cls +0 -930
  43. data/ext/minimap2/tex/blasr-mc.eval +0 -17
  44. data/ext/minimap2/tex/bowtie2-s3.sam.eval +0 -28
  45. data/ext/minimap2/tex/bwa-s3.sam.eval +0 -52
  46. data/ext/minimap2/tex/bwa.eval +0 -55
  47. data/ext/minimap2/tex/eval2roc.pl +0 -33
  48. data/ext/minimap2/tex/graphmap.eval +0 -4
  49. data/ext/minimap2/tex/hs38-simu.sh +0 -10
  50. data/ext/minimap2/tex/minialign.eval +0 -49
  51. data/ext/minimap2/tex/minimap2.bib +0 -460
  52. data/ext/minimap2/tex/minimap2.tex +0 -724
  53. data/ext/minimap2/tex/mm2-s3.sam.eval +0 -62
  54. data/ext/minimap2/tex/mm2-update.tex +0 -240
  55. data/ext/minimap2/tex/mm2.approx.eval +0 -12
  56. data/ext/minimap2/tex/mm2.eval +0 -13
  57. data/ext/minimap2/tex/natbib.bst +0 -1288
  58. data/ext/minimap2/tex/natbib.sty +0 -803
  59. data/ext/minimap2/tex/ngmlr.eval +0 -38
  60. data/ext/minimap2/tex/roc.gp +0 -60
  61. data/ext/minimap2/tex/snap-s3.sam.eval +0 -62
  62. data/ext/minimap2.patch +0 -19
  63. data/lib/minimap2/ffi/constants.rb +0 -267
  64. data/lib/minimap2/ffi/functions.rb +0 -245
  65. data/lib/minimap2/ffi/mappy.rb +0 -104
  66. data/lib/minimap2/ffi.rb +0 -27
@@ -1,389 +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 ds [true, false]
164
- # @param md [true, false]
165
- # @param max_frag_len [Integer]
166
- # @param extra_flags [Integer]
167
- # @note Name change: map -> align
168
- # In the Ruby language, the name map means iterator.
169
- # The original name is map, but here I use the method name align.
170
- # @note The use of Enumerator is being considered. The method names may change again.
171
- # @return [Array] alignments
172
-
173
- def align(
174
- seq, seq2 = nil,
175
- name: nil,
176
- buf: nil,
177
- cs: false,
178
- ds: false,
179
- md: false,
180
- max_frag_len: nil,
181
- extra_flags: nil
182
- )
183
- return if index.null?
184
- return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
185
-
186
- orig_map_opt_bytes = map_opt.to_ptr.read_bytes(FFI::MapOpt.size)
187
- orig_best_n = map_opt[:best_n]
188
-
189
- owned_buf = false
190
- if buf.nil?
191
- buf = FFI.mm_tbuf_init
192
- owned_buf = true
193
- end
194
-
195
- km = FFI.mm_tbuf_get_km(buf)
196
- alignments = []
197
-
198
- idx_parts = @indexes
199
- idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
200
-
201
- begin
202
- idx_parts.each do |idx_part|
203
- next if idx_part.nil? || idx_part.null?
204
-
205
- # Update options for this specific index part
206
- FFI.mm_mapopt_update(map_opt, idx_part)
207
-
208
- # Per-call options (do not leak across calls)
209
- map_opt[:flag] |= 4
210
- map_opt[:best_n] = orig_best_n
211
- map_opt[:max_frag_len] = max_frag_len if max_frag_len
212
- map_opt[:flag] |= extra_flags if extra_flags
213
-
214
- n_regs_ptr = ::FFI::MemoryPointer.new :int
215
- regs_ptr = FFI.mm_map_aux(idx_part, name, seq, seq2, n_regs_ptr, buf, map_opt)
216
- n_regs = n_regs_ptr.read_int
217
-
218
- next if regs_ptr.nil? || regs_ptr.null? || n_regs <= 0
219
-
220
- regs = Array.new(n_regs) do |i|
221
- FFI::Reg1.new(regs_ptr + i * FFI::Reg1.size)
222
- end
223
-
224
- hit = FFI::Hit.new
225
-
226
- cs_buf_ptr = nil
227
- m_cs_ptr = nil
228
- if cs || ds || md
229
- cs_buf_ptr = ::FFI::MemoryPointer.new(:pointer)
230
- cs_buf_ptr.write_pointer(::FFI::Pointer::NULL)
231
- m_cs_ptr = ::FFI::MemoryPointer.new(:int)
232
- m_cs_ptr.write_int(0)
233
- end
234
-
235
- i = 0
236
- begin
237
- while i < n_regs
238
- FFI.mm_reg2hitpy(idx_part, regs[i], hit)
239
-
240
- c = hit[:cigar32].read_array_of_uint32(hit[:n_cigar32])
241
- cigar = c.map { |x| [x >> 4, x & 0xf] } # 32-bit CIGAR encoding -> Ruby array
242
-
243
- _cs = ""
244
- _ds = ""
245
- _md = ""
246
- if cs || ds || md
247
- cur_seq = hit[:seg_id] > 0 && seq2 ? seq2 : seq
248
-
249
- if cs
250
- l_cs_str = FFI.mm_gen_cs(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq, 1)
251
- cs_ptr = cs_buf_ptr.read_pointer
252
- _cs = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
253
- end
254
-
255
- if ds
256
- l_cs_str = FFI.mm_gen_ds(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq, 1)
257
- cs_ptr = cs_buf_ptr.read_pointer
258
- _ds = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
259
- end
260
-
261
- if md
262
- l_cs_str = FFI.mm_gen_md(km, cs_buf_ptr, m_cs_ptr, idx_part, regs[i], cur_seq)
263
- cs_ptr = cs_buf_ptr.read_pointer
264
- _md = cs_ptr.null? || l_cs_str <= 0 ? "" : cs_ptr.read_string(l_cs_str)
265
- end
266
- end
267
-
268
- alignments << Alignment.new(hit, cigar, _cs, _ds, _md)
269
-
270
- FFI.mm_free_reg1(regs[i])
271
- i += 1
272
- end
273
- ensure
274
- while i < n_regs
275
- FFI.mm_free_reg1(regs[i])
276
- i += 1
277
- end
278
-
279
- if cs_buf_ptr
280
- cs_ptr = cs_buf_ptr.read_pointer
281
- FFI.mappy_free(cs_ptr) unless cs_ptr.nil? || cs_ptr.null?
282
- end
283
-
284
- # Free the mm_map/mm_map_aux return value array itself
285
- FFI.mappy_free(regs_ptr) unless regs_ptr.nil? || regs_ptr.null?
286
- end
287
- end
288
- ensure
289
- FFI.mm_tbuf_destroy(buf) if owned_buf
290
-
291
- # Restore map_opt to the state before this call
292
- map_opt.to_ptr.put_bytes(0, orig_map_opt_bytes)
293
- end
294
-
295
- if orig_best_n && orig_best_n > 0 && alignments.length > orig_best_n
296
- alignments.sort_by! do |aln|
297
- [
298
- aln.primary? ? 1 : 0,
299
- aln.mapq,
300
- aln.mlen,
301
- aln.blen,
302
- -aln.nm
303
- ]
304
- end
305
- alignments.reverse!
306
- alignments = alignments.take(orig_best_n)
307
- end
308
-
309
- alignments
310
- end
311
-
312
- # Retrieve a subsequence from the index.
313
- # @param name
314
- # @param start
315
- # @param stop
316
-
317
- def seq(name, start = 0, stop = 0x7fffffff)
318
- return if index.null?
319
- return if (map_opt[:flag] & 4).zero? && (index[:flag] & 2).zero?
320
-
321
- idx_parts = @indexes
322
- idx_parts = [index] if idx_parts.nil? || idx_parts.empty?
323
-
324
- idx_parts.each do |idx_part|
325
- next if idx_part.nil? || idx_part.null?
326
-
327
- lp = ::FFI::MemoryPointer.new(:int)
328
- s = FFI.mappy_fetch_seq(idx_part, name, start, stop, lp)
329
- l = lp.read_int
330
- if l == 0
331
- FFI.mappy_free(s) unless s.nil? || s.null?
332
- next
333
- end
334
-
335
- begin
336
- return s.read_string(l)
337
- ensure
338
- FFI.mappy_free(s) unless s.nil? || s.null?
339
- end
340
- end
341
-
342
- nil
343
- end
344
-
345
- # k-mer length, no larger than 28
346
-
347
- def k
348
- index[:k]
349
- end
350
-
351
- # minimizer window size, no larger than 255
352
-
353
- def w
354
- index[:w]
355
- end
356
-
357
- def n_seq
358
- return 0 if index.null?
359
-
360
- indexes = @indexes
361
- return index[:n_seq] if indexes.nil? || indexes.empty?
362
-
363
- indexes.sum { |idx| idx.nil? || idx.null? ? 0 : idx[:n_seq] }
364
- end
365
-
366
- def seq_names
367
- return [] if index.null?
368
-
369
- indexes = @indexes
370
- indexes = [index] if indexes.nil? || indexes.empty?
371
-
372
- names = []
373
- seen = {}
374
- indexes.each do |idx|
375
- next if idx.nil? || idx.null?
376
-
377
- ptr = idx[:seq].to_ptr
378
- idx[:n_seq].times do |i|
379
- name = FFI::IdxSeq.new(ptr + i * FFI::IdxSeq.size)[:name]
380
- next if seen[name]
381
-
382
- seen[name] = true
383
- names << name
384
- end
385
- end
386
- names
387
- end
388
71
  end
389
72
  end
@@ -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,24 +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.
43
47
  # @!attribute ds
44
- # @return [String] the ds tag.
48
+ # @return [String, nil] the ds tag.
45
49
  # @!attribute md
46
- # @return [String] the MD tag as in the SAM format.
47
- # 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.
48
51
  # @!attribute cigar_str
49
52
  # @return [String] CIGAR string.
50
53
 
51
54
  class Alignment
55
+ CIGAR_STR = "MIDNSHP=XB"
56
+
52
57
  def self.keys
53
- %i[ctg ctg_len r_st r_en strand trans_strand blen mlen nm primary
58
+ %i[qname qlen ctg ctg_len r_st r_en strand trans_strand blen mlen nm primary
54
59
  q_st q_en mapq cigar read_num cs ds md cigar_str]
55
60
  end
56
61
 
57
62
  attr_reader(*keys)
58
63
 
59
64
  def initialize(h, cigar, cs = nil, ds = nil, md = nil)
65
+ @qname = h[:qname]
66
+ @qlen = h[:qlen]
60
67
  @ctg = h[:ctg]
61
68
  @ctg_len = h[:ctg_len]
62
69
  @r_st = h[:ctg_start]
@@ -76,7 +83,7 @@ module Minimap2
76
83
  @ds = ds
77
84
  @md = md
78
85
 
79
- @cigar_str = cigar.map { |x| x[0].to_s + FFI::CIGAR_STR[x[1]] }.join
86
+ @cigar_str = cigar.map { |x| x[0].to_s + CIGAR_STR[x[1]] }.join
80
87
  end
81
88
 
82
89
  def primary?
@@ -89,7 +96,7 @@ module Minimap2
89
96
  self.class.keys.map { |k| [k, __send__(k)] }.to_h
90
97
  end
91
98
 
92
- # Convert to the PAF format without the QueryName and QueryLength columns.
99
+ # Convert to the PAF format.
93
100
 
94
101
  def to_s
95
102
  strand = if @strand > 0
@@ -107,7 +114,7 @@ module Minimap2
107
114
  else
108
115
  "ts:A:."
109
116
  end
110
- 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,
111
118
  @mlen, @blen, @mapq, tp, ts, "cg:Z:#{@cigar_str}"]
112
119
  a << "cs:Z:#{@cs}" unless @cs.nil? || @cs.empty?
113
120
  a << "ds:Z:#{@ds}" unless @ds.nil? || @ds.empty?
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Minimap2
4
- VERSION = "0.2.31.0"
4
+ # <binding major>.<minimap2 major>.<minimap2 minor>.<binding patch>
5
+ VERSION = "1.2.31.0"
5
6
  end