vienna_rna 0.8.6 → 0.9.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/lib/vienna_rna/global/parser.rb +19 -0
- data/lib/vienna_rna/global/rna.rb +115 -0
- data/lib/vienna_rna/global/rna_extensions.rb +109 -0
- data/lib/vienna_rna/{modules/graphing.rb → graphing/r.rb} +49 -111
- data/lib/vienna_rna/package/base.rb +117 -0
- data/lib/vienna_rna/package/energy_grid_2d.rb +69 -0
- data/lib/vienna_rna/package/eval.rb +11 -0
- data/lib/vienna_rna/package/fftbor.rb +19 -0
- data/lib/vienna_rna/package/fftbor2d.rb +25 -0
- data/lib/vienna_rna/package/fold.rb +31 -0
- data/lib/vienna_rna/package/heat.rb +15 -0
- data/lib/vienna_rna/package/rna2dfold.rb +27 -0
- data/lib/vienna_rna/package/rnabor.rb +32 -0
- data/lib/vienna_rna/package/subopt.rb +19 -0
- data/lib/vienna_rna/package/xbor.rb +63 -0
- data/lib/vienna_rna.rb +27 -14
- metadata +22 -38
- data/lib/vienna_rna/modules/base.rb +0 -124
- data/lib/vienna_rna/modules/batch.rb +0 -26
- data/lib/vienna_rna/modules/energy_grid_2d.rb +0 -63
- data/lib/vienna_rna/modules/eval.rb +0 -9
- data/lib/vienna_rna/modules/fftbor.rb +0 -21
- data/lib/vienna_rna/modules/fftbor2d.rb +0 -23
- data/lib/vienna_rna/modules/ffthairpin.rb +0 -4
- data/lib/vienna_rna/modules/fftmultiloop.rb +0 -4
- data/lib/vienna_rna/modules/fold.rb +0 -29
- data/lib/vienna_rna/modules/heat.rb +0 -13
- data/lib/vienna_rna/modules/parser.rb +0 -17
- data/lib/vienna_rna/modules/rna.rb +0 -113
- data/lib/vienna_rna/modules/rna2dfold.rb +0 -25
- data/lib/vienna_rna/modules/rna_extensions.rb +0 -101
- data/lib/vienna_rna/modules/rnabor.rb +0 -33
- data/lib/vienna_rna/modules/subopt.rb +0 -17
- data/lib/vienna_rna/modules/utils.rb +0 -34
- data/lib/vienna_rna/modules/xbor.rb +0 -64
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fc492c40bf3f4d1c52ecf1afd09810c9798471a
|
4
|
+
data.tar.gz: 2a7ea6a2eeaca132e055e6aacc3cb1f0456990ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16e9902e83a11b8143b598b565ce2d9acf78e0dcd59a89079cecace6d40e9eff4108fa331e1488ed29ce6b281d2d76a132e6fa84d377ec4a0c14004f19be1d2f
|
7
|
+
data.tar.gz: 191f17dea3941c52c2c990d29e881bd331bc96cdee50857f42f7acfa5b27a252c61966600e7e13e88a6f6fbbf75571afd5c31f0cd98cc75773060f96eb2f86fc
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Global
|
3
|
+
module Parser
|
4
|
+
REGEXP = {
|
5
|
+
mfe: / \(\s*(-?\d*\.\d*)\)$/
|
6
|
+
}
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def rnafold_mfe_structure(response)
|
10
|
+
response.split(/\n/)[1].split(/\s+/).first
|
11
|
+
end
|
12
|
+
|
13
|
+
def rnafold_mfe(response)
|
14
|
+
response.split(/\n/)[1].match(REGEXP[:mfe])[1].to_f
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Global
|
3
|
+
class Rna
|
4
|
+
include RnaExtensions
|
5
|
+
|
6
|
+
attr_reader :sequence, :structure, :second_structure, :raw_data
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def init_from_string(sequence, structure = nil, second_structure = nil)
|
10
|
+
new(
|
11
|
+
sequence: sequence,
|
12
|
+
structure: structure,
|
13
|
+
second_structure: second_structure
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def init_from_hash(hash)
|
18
|
+
new(
|
19
|
+
sequence: hash[:sequence] || hash[:seq],
|
20
|
+
structure: hash[:structure] || hash[:str_1] || hash[:str],
|
21
|
+
second_structure: hash[:second_structure] || hash[:str_2],
|
22
|
+
raw_data: hash
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def init_from_array(array)
|
27
|
+
init_from_string(*array)
|
28
|
+
end
|
29
|
+
|
30
|
+
def init_from_fasta(string)
|
31
|
+
string = File.read(string).chomp if File.exist?(string)
|
32
|
+
init_from_string(*string.split(/\n/).reject { |line| line.start_with?(">") }[0, 3])
|
33
|
+
end
|
34
|
+
|
35
|
+
def init_from_self(rna)
|
36
|
+
# This happens when you call a ViennaRna library function with the output of something like ViennaRna::Fold.run(...).mfe
|
37
|
+
new(
|
38
|
+
sequence: rna.sequence,
|
39
|
+
strucutre: rna.structure,
|
40
|
+
second_strucutre: rna.second_structure,
|
41
|
+
raw_data: rna.raw_data
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :placeholder, :new
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(sequence: "", structure: "", second_structure: "", raw_data: {})
|
49
|
+
@sequence, @raw_data = sequence, raw_data
|
50
|
+
|
51
|
+
[:structure, :second_structure].each do |structure_symbol|
|
52
|
+
instance_variable_set(
|
53
|
+
:"@#{structure_symbol}",
|
54
|
+
case structure_value = eval("#{structure_symbol}")
|
55
|
+
when :empty then empty_structure
|
56
|
+
when :mfe then RNA(sequence).run(:fold).mfe_rna.structure
|
57
|
+
when String then structure_value
|
58
|
+
end
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
if str && seq.length != str.length
|
63
|
+
ViennaRna.debugger { "The sequence length (%d) doesn't match the structure length (%d)" % [seq, str].map(&:length) }
|
64
|
+
end
|
65
|
+
|
66
|
+
if str_2 && str_1.length != str_2.length
|
67
|
+
ViennaRna.debugger { "The first structure length (%d) doesn't match the second structure length (%d)" % [str_1, str_2].map(&:length) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
alias :seq :sequence
|
72
|
+
alias :str :structure
|
73
|
+
alias :str_1 :structure
|
74
|
+
alias :str_2 :second_structure
|
75
|
+
|
76
|
+
def empty_structure
|
77
|
+
"." * seq.length
|
78
|
+
end
|
79
|
+
|
80
|
+
alias :empty_str :empty_structure
|
81
|
+
|
82
|
+
def write_fa!(filename, comment = nil)
|
83
|
+
filename.tap do |filename|
|
84
|
+
File.open(filename, ?w) do |file|
|
85
|
+
file.write("> %s\n" % comment) if comment
|
86
|
+
file.write("%s\n" % seq) if seq
|
87
|
+
file.write("%s\n" % str_1) if str_1
|
88
|
+
file.write("%s\n" % str_2) if str_2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def temp_fa_file!
|
94
|
+
write_fa!(Tempfile.new("")).path
|
95
|
+
end
|
96
|
+
|
97
|
+
def run(module_name, options = {})
|
98
|
+
if rna_module = ViennaRna.const_missing("#{module_name}".camelize)
|
99
|
+
rna_module.run(self, options)
|
100
|
+
else
|
101
|
+
raise ArgumentError.new("#{module_name} can't be resolved as an executable")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect
|
106
|
+
"#<%s>" % [
|
107
|
+
"#{self.class.name}",
|
108
|
+
("#{seq[0, 20] + (seq.length > 20 ? '...' : '')}" if seq && !seq.empty?),
|
109
|
+
("#{str_1[0, 20] + (str_1.length > 20 ? ' [truncated]' : '')}" if str_1 && !str_1.empty?),
|
110
|
+
("#{str_2[0, 20] + (str_2.length > 20 ? ' [truncated]' : '')}" if str_2 && !str_1.empty?),
|
111
|
+
].compact.join(" ")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Global
|
3
|
+
module RnaExtensions
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, InstanceMethods)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
base.extend(OneStructureBasedMethods)
|
8
|
+
base.extend(TwoStructureBasedMethods)
|
9
|
+
|
10
|
+
base.class_eval do
|
11
|
+
OneStructureBasedMethods.public_instance_methods.each do |class_method|
|
12
|
+
define_method(class_method) do |*args|
|
13
|
+
self.class.send(class_method, *[structure].concat(args))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
TwoStructureBasedMethods.public_instance_methods.each do |class_method|
|
18
|
+
define_method(class_method) do |*args|
|
19
|
+
self.class.send(class_method, *[str_1, str_2].concat(args))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
base.send(:include, InstanceMethods)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def generate_sequence(sequence_length)
|
29
|
+
# 0th order Markov chain w/ uniform probability distribution
|
30
|
+
Rna.init_from_string(sequence_length.times.inject("") { |string, _| string + %w[A U C G][rand(4)] })
|
31
|
+
end
|
32
|
+
|
33
|
+
def shuffle(sequence, token_length = 2)
|
34
|
+
Shuffle.new(sequence).shuffle(token_length)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module InstanceMethods
|
39
|
+
def dishuffle
|
40
|
+
self.class.shuffle(sequence, 2)
|
41
|
+
end
|
42
|
+
|
43
|
+
def gc_content
|
44
|
+
seq.split(//).select { |i| i =~ /[GC]/i }.size.to_f / seq.size
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
module OneStructureBasedMethods
|
49
|
+
def max_bp_distance(structure)
|
50
|
+
base_pairs(structure).count + ((structure.length - 3) / 2.0).floor
|
51
|
+
end
|
52
|
+
|
53
|
+
def base_pairs(structure)
|
54
|
+
get_pairings(structure).each_with_index.inject(Set.new) do |set, (j, i)|
|
55
|
+
j >= 0 ? set << Set[i, j] : set
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_pairings(structure)
|
60
|
+
stack = []
|
61
|
+
|
62
|
+
structure.each_char.each_with_index.inject(Array.new(structure.length, -1)) do |array, (symbol, index)|
|
63
|
+
array.tap do
|
64
|
+
case symbol
|
65
|
+
when "(" then stack.push(index)
|
66
|
+
when ")" then
|
67
|
+
if stack.empty?
|
68
|
+
raise "Too many ')' in '#{structure}'"
|
69
|
+
else
|
70
|
+
stack.pop.tap do |opening|
|
71
|
+
array[opening] = index
|
72
|
+
array[index] = opening
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end.tap do
|
78
|
+
raise "Too many '(' in '#{structure}'" unless stack.empty?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module TwoStructureBasedMethods
|
84
|
+
def bp_distance(structure_1, structure_2)
|
85
|
+
# Takes two structures and calculates the distance between them by |symmetric difference(bp_in_a, bp_in_b)|
|
86
|
+
raise "The two structures are not the same length" unless structure_1.length == structure_2.length
|
87
|
+
|
88
|
+
bp_set_1, bp_set_2 = base_pairs(structure_1), base_pairs(structure_2)
|
89
|
+
|
90
|
+
((bp_set_1 - bp_set_2) + (bp_set_2 - bp_set_1)).count
|
91
|
+
end
|
92
|
+
|
93
|
+
def symmetric_bp_distance(structure_1, structure_2)
|
94
|
+
# Takes two structures and calculates the distance between them by: sum { ((x_j - x_i) - (y_j - y_i)).abs }
|
95
|
+
raise "The two structures are not the same length" unless structure_1.length == structure_2.length
|
96
|
+
|
97
|
+
bp_dist = ->(array, i) { array[i] == -1 ? 0 : array[i] - i }
|
98
|
+
|
99
|
+
structure_1_pairings = get_pairings(structure_1)
|
100
|
+
structure_2_pairings = get_pairings(structure_2)
|
101
|
+
|
102
|
+
structure_1.length.times.inject(0) do |distance, i|
|
103
|
+
distance + (bp_dist[structure_1_pairings, i] - bp_dist[structure_2_pairings, i]).abs
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -9,31 +9,70 @@ module ViennaRna
|
|
9
9
|
raise unless e.message == "Unsupported data type on R's end"
|
10
10
|
end
|
11
11
|
end
|
12
|
-
|
13
|
-
def
|
12
|
+
|
13
|
+
def overlay(data, title: nil, type: ?l, x_label: "Independent", y_label: "Dependent", legend: "topleft", filename: false)
|
14
|
+
# data: [{ data: [[x_0, y_0], ..., [x_n, y_n]], legend: "Line 1" }, ...]
|
15
|
+
|
16
|
+
x_points = data.map { |hash| hash[:data].map(&:first) }
|
17
|
+
y_points = data.map { |hash| hash[:data].map(&:last) }
|
18
|
+
x_range = Range.new(x_points.map(&:min).min.floor, x_points.map(&:max).max.ceil)
|
19
|
+
y_range = Range.new(y_points.map(&:min).min.floor, y_points.map(&:max).max.ceil)
|
20
|
+
|
14
21
|
graph do |r|
|
15
|
-
r.assign("line_graph.x", data.map(&:first))
|
16
|
-
r.assign("line_graph.y", data.map(&:last))
|
17
|
-
|
18
22
|
r.eval("%s('%s', 6, 6)" % [
|
19
23
|
writing_file?(filename) ? "pdf" : "quartz",
|
20
24
|
writing_file?(filename) ? filename : "Graph",
|
21
25
|
])
|
22
26
|
|
27
|
+
r.assign("legend.titles", data.each_with_index.map { |hash, index| hash[:legend] || "Line #{index + 1}" })
|
28
|
+
r.eval("line.colors <- rainbow(%d)" % data.size)
|
29
|
+
r.eval("plot(0, 0, type = 'n', cex = .75, xlab = '', ylab = '', xlim = c(%d, %d), ylim = c(%d, %d))" % [
|
30
|
+
x_range.min, x_range.max, y_range.min, y_range.max
|
31
|
+
])
|
32
|
+
|
33
|
+
data.each_with_index do |hash, index|
|
34
|
+
r.assign("line_graph.x.%d" % index, x_points[index])
|
35
|
+
r.assign("line_graph.y.%d" % index, y_points[index])
|
36
|
+
|
37
|
+
r.eval <<-STR
|
38
|
+
lines(
|
39
|
+
line_graph.x.#{index},
|
40
|
+
line_graph.y.#{index},
|
41
|
+
col = line.colors[#{index + 1}],
|
42
|
+
type = "#{type}",
|
43
|
+
pch = #{index}
|
44
|
+
)
|
45
|
+
STR
|
46
|
+
end
|
47
|
+
|
23
48
|
r.eval <<-STR
|
24
|
-
|
25
|
-
line_graph.x,
|
26
|
-
line_graph.y,
|
49
|
+
title(
|
27
50
|
xlab = "#{x_label}",
|
28
51
|
ylab = "#{y_label}",
|
29
|
-
main = "#{title || 'Line Graph'}"
|
30
|
-
type = "#{type}"
|
52
|
+
main = "#{title || 'Line Graph'}"
|
31
53
|
)
|
32
54
|
STR
|
55
|
+
|
56
|
+
if legend
|
57
|
+
r.eval <<-STR
|
58
|
+
legend(
|
59
|
+
"#{legend}",
|
60
|
+
legend.titles,
|
61
|
+
bty = "n",
|
62
|
+
col = line.colors,
|
63
|
+
lty = rep(1, #{data.size}),
|
64
|
+
pch = 0:#{data.size}
|
65
|
+
)
|
66
|
+
STR
|
67
|
+
end
|
33
68
|
|
34
69
|
r.eval("dev.off()") if writing_file?(filename)
|
35
70
|
end
|
36
71
|
end
|
72
|
+
|
73
|
+
def line_graph(data, title: nil, type: ?l, x_label: "Independent", y_label: "Dependent", filename: false)
|
74
|
+
overlay([{ data: data }], title: title, type: type, x_label: x_label, y_label: y_label, legend: false, filename: filename)
|
75
|
+
end
|
37
76
|
|
38
77
|
def histogram(data, title: nil, x_label: "Bins", bin_size: 1, relative: false, filename: false)
|
39
78
|
half = bin_size / 2.0
|
@@ -150,106 +189,5 @@ module ViennaRna
|
|
150
189
|
end
|
151
190
|
end
|
152
191
|
end
|
153
|
-
|
154
|
-
module Gnuplot
|
155
|
-
class << self
|
156
|
-
def plot(data, options = {})
|
157
|
-
Gnuplot.open do |gnuplot|
|
158
|
-
Gnuplot::Plot.new(gnuplot) do |plot|
|
159
|
-
plot.autoscale
|
160
|
-
|
161
|
-
case options[:output]
|
162
|
-
when /file/i then
|
163
|
-
plot.output(options[:filename])
|
164
|
-
plot.terminal("png size %s" % (options[:dimensions] || "800,600"))
|
165
|
-
end
|
166
|
-
|
167
|
-
(options[:plot] || {}).keys.each do |option|
|
168
|
-
plot.send(option, options[:plot][option])
|
169
|
-
end
|
170
|
-
|
171
|
-
plot.data = data.map do |data_hash|
|
172
|
-
Gnuplot::DataSet.new([data_hash[:x], data_hash[:y]]) do |dataset|
|
173
|
-
dataset.with = data_hash[:style] || "points"
|
174
|
-
dataset.linecolor = "rgb '#{data_hash[:color]}'" if data_hash[:color]
|
175
|
-
|
176
|
-
data_hash[:title] ? dataset.title = data_hash[:title] : dataset.notitle
|
177
|
-
end
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def splot(data, options = {})
|
184
|
-
# [[x_1, y_1, z_1], [x_2, y_2, z_2], ...]
|
185
|
-
orthogonal_data = data.inject([[], [], []]) { |array, list| array.zip(list).map { |a, e| a << e } }
|
186
|
-
|
187
|
-
Gnuplot.open do |gnuplot|
|
188
|
-
Gnuplot::SPlot.new(gnuplot) do |plot|
|
189
|
-
plot.autoscale
|
190
|
-
|
191
|
-
case options[:output]
|
192
|
-
when /file/i then
|
193
|
-
plot.output(options[:filename])
|
194
|
-
plot.terminal("png size 800,600")
|
195
|
-
end
|
196
|
-
|
197
|
-
(options[:plot] || {}).keys.each do |option|
|
198
|
-
plot.send(option, options[:plot][option])
|
199
|
-
end
|
200
|
-
|
201
|
-
plot.data = [
|
202
|
-
Gnuplot::DataSet.new(orthogonal_data) do |dataset|
|
203
|
-
dataset.with = options[:style] || "lines"
|
204
|
-
end
|
205
|
-
]
|
206
|
-
end
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
def histogram(data, title = "", options = {})
|
211
|
-
bin_size = options.delete(:bin_size) || 1
|
212
|
-
half = bin_size / 2.0
|
213
|
-
range = Range.new((data.min - half).floor, (data.max + half).ceil)
|
214
|
-
groups = (range.min + half).step(range.max, bin_size).map { |x| [x, data.count { |i| i >= x - half && i < x + half }] }
|
215
|
-
|
216
|
-
options.merge!(output: "file") if options[:filename]
|
217
|
-
options[:plot] = (options[:plot] || {}).merge({
|
218
|
-
title: title,
|
219
|
-
yrange: "[0:#{groups.map(&:last).max * 1.1}]",
|
220
|
-
xtics: "#{[bin_size, 5].max}",
|
221
|
-
style: "fill solid 0.5 border"
|
222
|
-
})
|
223
|
-
|
224
|
-
plot([{ x: groups.map(&:first), y: groups.map(&:last), style: "boxes" }], options)
|
225
|
-
end
|
226
|
-
|
227
|
-
def roc(data, title = "", options = {})
|
228
|
-
# data = [[true_score_1, true_score_2, ...], [false_score_1, false_score_2, ...]]~
|
229
|
-
roc_curve = ROC.curve_points({ 1 => data[0], -1 => data[1] }.inject([]) { |data, (truth, values)| data.concat(values.map { |i| [i, truth] })})
|
230
|
-
area = roc_curve.each_cons(2).inject(0) do |sum, (a, b)|
|
231
|
-
delta_x, delta_y = b[0] - a[0], b[1] - a[1]
|
232
|
-
sum + (delta_x * delta_y / 2 + delta_x * [a[1], b[1]].min)
|
233
|
-
end
|
234
|
-
|
235
|
-
options.merge!(output: "file") if options[:filename]
|
236
|
-
options.merge!({ plot: { title: "%s %s %.4f" % [title, "AUC:", area] } })
|
237
|
-
|
238
|
-
plot([{ x: roc_curve.map(&:first), y: roc_curve.map(&:last), style: "lines" }], options)
|
239
|
-
end
|
240
|
-
|
241
|
-
def quick_plot(data, title = "", options = {})
|
242
|
-
quick_overlay([{ data: data }], title, options)
|
243
|
-
end
|
244
|
-
|
245
|
-
def quick_overlay(data, title = "", options = {})
|
246
|
-
# [{ data: [[x_0, y_0], [x_1, y_1], ...], label: "Label" }, { data: [[x_0, y_0], [x_1, y_1], ...] }]
|
247
|
-
options[:plot] = ((options[:plot] || {}).merge(title: title))
|
248
|
-
options.merge!(output: "file") if options[:filename]
|
249
|
-
|
250
|
-
plot(data.map { |hash| { title: hash[:label], x: hash[:data].map(&:first), y: hash[:data].map(&:last), style: "linespoints" }.merge(hash[:options] || {}) }, options)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
192
|
end
|
255
193
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Package
|
3
|
+
class Base
|
4
|
+
class_attribute :executable_name
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def method_added(name)
|
8
|
+
if name == :run
|
9
|
+
unless @chaining
|
10
|
+
@chaining = true
|
11
|
+
alias_method_chain :run, :hooks
|
12
|
+
else
|
13
|
+
remove_instance_variable(:@chaining)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def exec_exists?(name)
|
19
|
+
!%x[which RNA#{name.to_s.downcase}].empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(*data)
|
23
|
+
flags = data.length > 1 && data.last.is_a?(Hash) ? data.pop : {}
|
24
|
+
new(data).run(flags)
|
25
|
+
end
|
26
|
+
|
27
|
+
def bootstrap(data: nil, output: "")
|
28
|
+
new(data).tap do |object|
|
29
|
+
object.instance_variable_set(:@response, File.exist?(output) ? File.read(output).chomp : output)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :data, :response, :runtime
|
35
|
+
|
36
|
+
def exec_name
|
37
|
+
if executable_name
|
38
|
+
executable_name.respond_to?(:call) ? self.class.module_exec(&executable_name) : executable_name
|
39
|
+
else
|
40
|
+
"RNA#{self.class.name.split('::').last.underscore}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def exec_sequence_format
|
45
|
+
if data.str
|
46
|
+
'"%s
|
47
|
+
%s"' % [data.seq, data.str]
|
48
|
+
else
|
49
|
+
data.seq
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize(data)
|
54
|
+
data = [data] unless data.is_a?(Array)
|
55
|
+
|
56
|
+
@data = case data.map(&:class)
|
57
|
+
when [ViennaRna::Global::Rna] then data.first
|
58
|
+
when *(1..3).map { |i| [String] * i } then RNA.from_string(*data)
|
59
|
+
when [Hash] then RNA.from_hash(*data)
|
60
|
+
when [Array] then RNA.from_array(*data)
|
61
|
+
when [NilClass] then ViennaRna::Global::Rna.placeholder
|
62
|
+
else raise TypeError.new("Unsupported ViennaRna::Global::Rna#initialize format: #{data}")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def run_with_hooks(flags = {})
|
67
|
+
unless @response
|
68
|
+
tap do
|
69
|
+
@runtime = Benchmark.measure do
|
70
|
+
pre_run_check unless respond_to?(:run_command)
|
71
|
+
@response = run_without_hooks(flags)
|
72
|
+
post_process if respond_to?(:post_process)
|
73
|
+
end
|
74
|
+
|
75
|
+
ViennaRna.debugger { "Total runtime: %.3f sec." % runtime.real }
|
76
|
+
end
|
77
|
+
else
|
78
|
+
self
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def pre_run_check
|
83
|
+
if %x[which #{exec_name}].empty?
|
84
|
+
raise RuntimeError.new("#{exec_name} is not defined on this machine")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def stringify_flags(flags)
|
89
|
+
base_flags = self.class.const_defined?(:BASE_FLAGS) ? self.class.const_get(:BASE_FLAGS) : {}
|
90
|
+
|
91
|
+
flags.merge(base_flags).inject("") do |string, (flag, value)|
|
92
|
+
(string + (value == :empty ? " -%s" % flag : " -%s %s" % [flag, value])).strip
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def run(flags = {})
|
97
|
+
command = if respond_to?(:run_command)
|
98
|
+
method(:run_command).arity.zero? ? run_command : run_command(flags)
|
99
|
+
else
|
100
|
+
"echo #{exec_sequence_format} | #{exec_name} #{stringify_flags(flags)}"
|
101
|
+
end
|
102
|
+
|
103
|
+
ViennaRna.debugger { command }
|
104
|
+
|
105
|
+
%x[#{command}]
|
106
|
+
end
|
107
|
+
|
108
|
+
def serialize
|
109
|
+
YAML.dump(self)
|
110
|
+
end
|
111
|
+
|
112
|
+
def debugger(&block)
|
113
|
+
self.class.debugger(&block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Package
|
3
|
+
class EnergyGrid2d < Base
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def self.inherited(subclass)
|
7
|
+
subclass.class_eval { prepend EnergyGrid2dWrapper }
|
8
|
+
end
|
9
|
+
|
10
|
+
module EnergyGrid2dWrapper
|
11
|
+
def distribution
|
12
|
+
super.map { |row| Row2d.new(*row) }.select { |row| row.p > 0 }.sort
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Row2d
|
17
|
+
attr_reader :i, :j, :p, :ensemble
|
18
|
+
|
19
|
+
def initialize(i, j, p, ensemble)
|
20
|
+
@i, @j, @p, @ensemble = i.to_i, j.to_i, BigDecimal.new(p.to_s), BigDecimal.new(ensemble.to_s)
|
21
|
+
end
|
22
|
+
|
23
|
+
def position
|
24
|
+
[i, j]
|
25
|
+
end
|
26
|
+
|
27
|
+
def <=>(other_row)
|
28
|
+
i == other_row.i ? j <=> other_row.j : i <=> other_row.i
|
29
|
+
end
|
30
|
+
|
31
|
+
def inspect
|
32
|
+
"#<Row2d (%d, %d), p: %s, ensemble: %s>" % [i, j, p, ensemble]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.aligned_distributions(*energy_grids)
|
37
|
+
point_set = set_of_points(*energy_grids)
|
38
|
+
|
39
|
+
energy_grids.map do |grid|
|
40
|
+
(grid.distribution + (point_set - grid.map(&:position)).map { |i, j| Row2d.new(i, j, 0, Float::INFINITY) }).sort
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.set_of_points(*energy_grids)
|
45
|
+
energy_grids.inject([]) { |list, grid| list + grid.map(&:position) }.uniq.sort
|
46
|
+
end
|
47
|
+
|
48
|
+
def each(&block)
|
49
|
+
distribution.each(&block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def quick_plot(num_colors: 8)
|
53
|
+
Graphing::R.matrix_heatmap(
|
54
|
+
distribution.map(&:i),
|
55
|
+
distribution.map(&:j),
|
56
|
+
distribution.map { |row| Math.log(row.p) },
|
57
|
+
title: "#{self.class.name} Matrix Heatmap",
|
58
|
+
x_label: "Distance from structure 2",
|
59
|
+
y_label: "Distance from structure 1",
|
60
|
+
num_colors: num_colors
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def inspect
|
65
|
+
"#<#{self.class.name} on #{data.inspect}>"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Package
|
3
|
+
class Fftbor < Xbor
|
4
|
+
def partition
|
5
|
+
response.split(/\n/).find { |line| line =~ /^Scaling factor.*:\s+(\d+\.\d+)/ }
|
6
|
+
BigDecimal.new($1)
|
7
|
+
end
|
8
|
+
|
9
|
+
def total_count
|
10
|
+
response.split(/\n/).find { |line| line =~ /^Number of structures: (\d+)/ }
|
11
|
+
$1.to_i
|
12
|
+
end
|
13
|
+
|
14
|
+
def distribution
|
15
|
+
self.class.parse(response).map { |row| BigDecimal.new(row[1]) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ViennaRna
|
2
|
+
module Package
|
3
|
+
class Fftbor2d < EnergyGrid2d
|
4
|
+
BASE_FLAGS = {
|
5
|
+
S: :empty
|
6
|
+
}
|
7
|
+
|
8
|
+
self.executable_name = "FFTbor2D"
|
9
|
+
|
10
|
+
def run_command(flags = {})
|
11
|
+
ViennaRna.debugger { "Running #{exec_name} on #{data.inspect}" }
|
12
|
+
|
13
|
+
"%s %s %s" % [
|
14
|
+
exec_name,
|
15
|
+
stringify_flags(BASE_FLAGS.merge(self.class.const_defined?(:FLAGS) ? self.class.const_get(:FLAGS) : {}).merge(flags)),
|
16
|
+
data.temp_fa_file!
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
def distribution
|
21
|
+
response.split(/\n/).map { |line| line.split(/\t/) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|