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,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
@@ -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 + FFI::CIGAR_STR[x[1]] }.join
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 without the QueryName and QueryLength columns.
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}" if @cs
110
- a << "MD:Z:#{@md}" if @md
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
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Minimap2
4
- VERSION = "0.2.30.3"
4
+ # <binding major>.<minimap2 major>.<minimap2 minor>.<binding patch>
5
+ VERSION = "1.2.31.0"
5
6
  end