mspire-simulator 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +46 -3
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/mspire-simulator +8 -0
- data/bin/sim_mail +2 -2
- data/lib/cv_parser.rb +7 -0
- data/lib/ms/curvefit/curve_fit_helper.rb +26 -20
- data/lib/ms/curvefit/mzml_reader.rb +1 -1
- data/lib/ms/curvefit.rb +25 -8
- data/lib/ms/isoelectric_calc.rb +162 -103
- data/lib/ms/merger.rb +46 -33
- data/lib/ms/mzml_wrapper.rb +74 -29
- data/lib/ms/noise.rb +28 -28
- data/lib/ms/rt/rt_helper.rb +3 -3
- data/lib/ms/rt/rtgenerator.rb +63 -51
- data/lib/ms/rt/weka.rb +17 -17
- data/lib/ms/sim_digester.rb +45 -26
- data/lib/ms/sim_feature.rb +180 -122
- data/lib/ms/sim_peptide.rb +58 -55
- data/lib/ms/sim_spectra.rb +22 -23
- data/lib/ms/sim_trollop.rb +36 -32
- data/lib/ms/tr_file_writer.rb +111 -98
- data/lib/progress.rb +21 -20
- data/mspire-simulator.gemspec +5 -5
- data/spec/file_writer_spec.rb +2 -1
- data/spec/merger_spec.rb +2 -1
- data/spec/ms-simulate_spec.rb +1 -1
- data/spec/peptide_spec.rb +2 -1
- data/spec/spec_helper.rb +8 -3
- data/spec/spectra_spec.rb +4 -3
- metadata +5 -5
- data/spec/progress_spec.rb +0 -22
data/README.rdoc
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
=
|
1
|
+
= mspire-simulator
|
2
2
|
|
3
3
|
Description:
|
4
|
-
Simulates MS runs given amino acid
|
4
|
+
Simulates MS runs given amino acid FASTA files. Outputs a .mzML file.
|
5
5
|
|
6
6
|
== Install
|
7
7
|
gem install mspire-simulator
|
@@ -10,8 +10,51 @@ Dependencies:
|
|
10
10
|
weka 3.6.0 - May need to add to CLASSPATH see: http://weka.wikispaces.com/CLASSPATH+problems
|
11
11
|
fftw 3.2.2 - Tested in Linux Mint 12 and Ubuntu Oneiric Ocelot
|
12
12
|
== Examples
|
13
|
-
|
13
|
+
The simplest way to run mspire-simulator is to give it a MZML file
|
14
|
+
with a single centroided elution profile from which, the simulator
|
15
|
+
can extract needed parameters including:
|
16
|
+
- Elution parameters: front, tail, and mu
|
17
|
+
- Overlap range (for merging signals)
|
18
|
+
- Sampling rate
|
19
|
+
- m/z wobble parameters: wobA, wobB
|
20
|
+
- Intensity variance parameters: jagA, jagB, jagC
|
21
|
+
|
22
|
+
$ mspire-simulator --mzml input.mzml [options] <.fasta file>
|
23
|
+
|
24
|
+
Alternatively all parameters can be specified on the command line:
|
25
|
+
|
26
|
+
$ mspire-simulator -r 3000 -s 1.0 -n false ...
|
27
|
+
|
28
|
+
To see all the available options:
|
29
|
+
|
30
|
+
$ mspire-simulator --help
|
31
|
+
|
32
|
+
|
33
|
+
=== Charge State Calculator
|
34
|
+
$ ruby lib/ms/isoelectric_calc.rb --ph 2 --distribution DRVYIHPFHL DRVYIHPF RVYIHPF VYIHPF
|
35
|
+
|
36
|
+
will return:
|
37
|
+
|
38
|
+
DRVYIHPFHL @ pH 2.0: +3, 29.040854; +4, 70.959146
|
39
|
+
|
40
|
+
DRVYIHPF @ pH 2.0: +2, 29.045885; +3, 70.954115
|
41
|
+
|
42
|
+
RVYIHPF @ pH 2.0: +2, 37.364123; +3, 62.635877
|
43
|
+
|
44
|
+
VYIHPF @ pH 2.0: +1, 40.341305; +2, 59.658695
|
45
|
+
|
46
|
+
To see all the available options:
|
47
|
+
$ ruby lib/ms/isoelectric_calc.rb --help
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
== TODO
|
52
|
+
Because of the many options and parameters to specify we will be moving
|
53
|
+
to a .init file format with a .init file editor.
|
54
|
+
|
55
|
+
Other improvments to mspire simulator are also pending.
|
14
56
|
== Copyright
|
15
57
|
|
16
58
|
See LICENSE.txt for further details.
|
17
59
|
|
60
|
+
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'jeweler'
|
|
5
5
|
Jeweler::Tasks.new do |gem|
|
6
6
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
7
7
|
gem.name = "mspire-simulator"
|
8
|
-
gem.homepage = "
|
8
|
+
gem.homepage = "https://github.com/princelab/mspire-simulator"
|
9
9
|
gem.license = "MIT"
|
10
10
|
gem.summary = %Q{Simulates MS1 runs given amino acid FASTA files. Outputs an MZML file.}
|
11
11
|
gem.description = %Q{Simulates MS1 runs given amino acid FASTA files. Outputs an MZML file.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bin/mspire-simulator
CHANGED
@@ -19,6 +19,8 @@ require 'ms/sim_digester'
|
|
19
19
|
require 'ms/sim_trollop'
|
20
20
|
require 'ms/merger'
|
21
21
|
|
22
|
+
|
23
|
+
|
22
24
|
module MspireSimulator
|
23
25
|
@opts = MS::Troll.new.get
|
24
26
|
begin
|
@@ -40,6 +42,10 @@ module MspireSimulator
|
|
40
42
|
|
41
43
|
module_function
|
42
44
|
def opts; @opts end
|
45
|
+
|
46
|
+
|
47
|
+
SampleLoad = 1.0 # Instrument dependent scaling, for an Orbitrap, assumed to be 1 ug
|
48
|
+
# TODO define an option for sample loading, and a scaling function to define the peak intensities
|
43
49
|
|
44
50
|
#------------------------Digest-----------------------------------------------
|
45
51
|
peptides = []
|
@@ -80,10 +86,12 @@ module MspireSimulator
|
|
80
86
|
#-----------------------------------------------------------------------------
|
81
87
|
|
82
88
|
|
89
|
+
|
83
90
|
#-----------------------Merge Finish------------------------------------------
|
84
91
|
spectra.spectra = Merger.compact(spectra.spectra)
|
85
92
|
#-----------------------------------------------------------------------------
|
86
93
|
|
94
|
+
|
87
95
|
|
88
96
|
#-----------------------Clean UP----------------------------------------------
|
89
97
|
spectra.features.each{|fe| fe.delete}
|
data/bin/sim_mail
CHANGED
@@ -18,9 +18,9 @@ begin
|
|
18
18
|
:password => 'chromatography',
|
19
19
|
:authentication => :plain,
|
20
20
|
:domain => "localhost.localdomain"
|
21
|
-
|
21
|
+
},
|
22
22
|
:subject => 'Mspire-Simulator', :body => msgbody
|
23
|
-
|
23
|
+
)
|
24
24
|
rescue
|
25
25
|
puts "Email function failed. Check email address and internet connection."
|
26
26
|
end
|
data/lib/cv_parser.rb
ADDED
@@ -35,10 +35,10 @@ class GenCurvefit
|
|
35
35
|
init_population
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
attr_reader :function, :paramsize, :mutation_limits, :population, :generations, :popsize
|
40
40
|
attr_writer :paramsize, :mutation_limits, :population, :generations, :popsize
|
41
|
-
|
41
|
+
|
42
42
|
def init_population
|
43
43
|
@popsize.times do
|
44
44
|
set = []
|
@@ -50,24 +50,24 @@ class GenCurvefit
|
|
50
50
|
@population<<set
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
def set_fit_function(func)
|
55
55
|
@function = func
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
def mutate(set)
|
59
59
|
index = rand(set.size-1)
|
60
60
|
limits = @mutation_limits[index]
|
61
61
|
set[index] += random_float(limits[0],limits[1])
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def self.smoothave(arr)
|
65
65
|
smooth_ave = [nil,nil,nil]
|
66
66
|
queue = []
|
67
67
|
arr.each do |i|
|
68
68
|
queue.push(i)
|
69
69
|
if queue.size > 7
|
70
|
-
|
70
|
+
queue.shift
|
71
71
|
end
|
72
72
|
smooth_ave<<queue.inject(:+)/queue.size if queue.size == 7
|
73
73
|
end
|
@@ -76,16 +76,16 @@ class GenCurvefit
|
|
76
76
|
end
|
77
77
|
return smooth_ave
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
def self.normalize(arr)
|
81
81
|
max = arr.max
|
82
82
|
arr.map!{|i| (i.to_f/max) * 100}
|
83
83
|
end
|
84
|
-
|
84
|
+
|
85
85
|
def sort_by_fitness
|
86
86
|
@population.sort_by!{|set| set.last}
|
87
87
|
end
|
88
|
-
|
88
|
+
|
89
89
|
def random_float(a,b)
|
90
90
|
a = a.to_f
|
91
91
|
b = b.to_f
|
@@ -94,15 +94,15 @@ class GenCurvefit
|
|
94
94
|
r = random * diff
|
95
95
|
return a + r
|
96
96
|
end
|
97
|
-
|
97
|
+
|
98
98
|
def rmsd(v,w)
|
99
99
|
n = v.size
|
100
100
|
sum = 0.0
|
101
101
|
n.times{|i| sum += ((v[i][0]-w[i][0])**2.0 + (v[i][1]-w[i][1])**2.0) }
|
102
102
|
return Math.sqrt( (1/n.to_f) * sum )
|
103
103
|
end
|
104
|
-
|
105
|
-
|
104
|
+
|
105
|
+
|
106
106
|
def fitness(set,pts_in,plot = false)
|
107
107
|
pts = []
|
108
108
|
xs = pts_in.transpose[0]
|
@@ -110,18 +110,24 @@ class GenCurvefit
|
|
110
110
|
fit_pt = function.call(set,x)
|
111
111
|
pts<<[x,fit_pt]
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
if plot
|
115
115
|
return pts
|
116
116
|
end
|
117
|
-
|
117
|
+
|
118
118
|
return rmsd(pts_in,pts)
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
def fit
|
122
|
-
|
122
|
+
prog = Progress.new("Generation")
|
123
|
+
num = 0
|
124
|
+
total = @generations
|
125
|
+
step = total/100
|
123
126
|
@generations.times do |i|
|
124
|
-
|
127
|
+
if i > step * (num + 1)
|
128
|
+
num = ((i/total.to_f)*100).to_i
|
129
|
+
prog.update(num," #{i+1}:")
|
130
|
+
end
|
125
131
|
#Generate mutations
|
126
132
|
index = rand(@popsize)
|
127
133
|
clone = @population[index].clone
|
@@ -139,14 +145,14 @@ class GenCurvefit
|
|
139
145
|
@best = @population.first
|
140
146
|
end
|
141
147
|
end
|
142
|
-
|
148
|
+
prog.finish!
|
143
149
|
return @best
|
144
150
|
end
|
145
|
-
|
151
|
+
|
146
152
|
def plot(file,labels = nil)
|
147
153
|
pts = fitness(@best,@pts_in,true)
|
148
154
|
Fit_plot.plot(@pts_in,pts,file,labels)
|
149
155
|
puts " Output File: #{file}"
|
150
156
|
end
|
151
|
-
|
157
|
+
|
152
158
|
end
|
data/lib/ms/curvefit.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
-
|
1
|
+
require 'progress'
|
2
2
|
require 'ms/curvefit/mzml_reader'
|
3
3
|
require 'ms/curvefit/curve_fit_helper'
|
4
4
|
|
5
|
+
@@avg_mz = 0
|
6
|
+
@@avg_rt = 0
|
7
|
+
|
5
8
|
class CurveFit
|
6
9
|
def self.get_parameters(opts)
|
7
10
|
data = Mzml_reader.get_data(opts[:mzml])
|
8
11
|
generations = opts[:generations]
|
9
|
-
|
12
|
+
|
10
13
|
@pts_int_var = []
|
11
14
|
@pts_mz_var = []
|
12
15
|
@pts_elut = []
|
@@ -17,13 +20,16 @@ class CurveFit
|
|
17
20
|
rts_in = data[1]
|
18
21
|
ints_in = data[2]
|
19
22
|
|
23
|
+
@@avg_mz = mzs_in.inject(:+)/mzs_in.size.to_f
|
24
|
+
@@avg_rt = rts_in.inject(:+)/rts_in.size.to_f
|
25
|
+
|
20
26
|
ints_in = GenCurvefit.normalize(ints_in)
|
21
27
|
#-----------------------overlapRange--------------------------------------------
|
22
28
|
mean = mzs_in.inject(:+)/mzs_in.size
|
23
29
|
opts[:overlapRange] = (mzs_in.sample_variance(mean)*10**6)/4
|
24
30
|
#-------------------------------------------------------------------------------
|
25
|
-
|
26
|
-
|
31
|
+
|
32
|
+
|
27
33
|
#----------------------create points/curve to fit elution-----------------------
|
28
34
|
ints_in.each_with_index do |s,i|
|
29
35
|
@pts_elut<<[rts_in[i],s]
|
@@ -46,8 +52,8 @@ class CurveFit
|
|
46
52
|
labels = ["retention time","normalized intensity"]
|
47
53
|
a_fit.plot("elution_curvefit.svg",labels)
|
48
54
|
#-------------------------------------------------------------------------------
|
49
|
-
|
50
|
-
|
55
|
+
|
56
|
+
|
51
57
|
#-----------------create points/curve to fit m/z variance-----------------------
|
52
58
|
wobs = []
|
53
59
|
mean = mzs_in.inject(:+)/mzs_in.size
|
@@ -77,7 +83,7 @@ class CurveFit
|
|
77
83
|
labels = ["normalized intensity","m/z variance"]
|
78
84
|
b_fit.plot("mz_var_curvefit.svg",labels)
|
79
85
|
#-------------------------------------------------------------------------------
|
80
|
-
|
86
|
+
|
81
87
|
#--------------------create points/curve to fit intensity variance--------------
|
82
88
|
smooth_ave = GenCurvefit.smoothave(ints_in)
|
83
89
|
|
@@ -114,7 +120,18 @@ class CurveFit
|
|
114
120
|
labels = ["normalized intensity","intensity variance"]
|
115
121
|
c_fit.plot("intensity_var_curvefit.svg",labels)
|
116
122
|
#-------------------------------------------------------------------------------
|
117
|
-
|
123
|
+
|
118
124
|
return opts
|
119
125
|
end
|
120
126
|
end
|
127
|
+
=begin
|
128
|
+
out_file = File.open("mzvar_params.txt","w")
|
129
|
+
out_file.puts "wobA\twobB\tavg_mz\tavg_rt"
|
130
|
+
ARGV.each do |file|
|
131
|
+
p file
|
132
|
+
opts = {:mzml => file, :generations => 30000}
|
133
|
+
opts = CurveFit.get_parameters(opts)
|
134
|
+
out_file.puts "#{opts[:wobA]}\t#{opts[:wobB]}\t#{@@avg_mz}\t#{@@avg_rt}"
|
135
|
+
end
|
136
|
+
out_file.close
|
137
|
+
=end
|
data/lib/ms/isoelectric_calc.rb
CHANGED
@@ -4,119 +4,178 @@
|
|
4
4
|
|
5
5
|
Precision = 0.001
|
6
6
|
ResidueTable = {
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# These are the fringe cases... B and Z... Jerks, these are harder to calculate pIs
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
7
|
+
:K => [2.18,8.95,10.53],
|
8
|
+
:E => [2.19,9.67,4.25],
|
9
|
+
:D => [1.88,9.60,3.65],
|
10
|
+
:H => [1.82,9.17,6.00],
|
11
|
+
:R => [2.17,9.04,12.48],
|
12
|
+
:Q => [2.17,9.13,nil],
|
13
|
+
:N => [2.02,8.80,nil],
|
14
|
+
:C => [1.96,10.28,8.18],
|
15
|
+
:T => [2.11,9.62,nil],
|
16
|
+
:S => [2.21,9.15,nil],
|
17
|
+
:W => [2.38,9.39,nil],
|
18
|
+
:Y => [2.20,9.11,10.07],
|
19
|
+
:F => [1.83,9.13,nil],
|
20
|
+
:M => [2.28,9.21,nil],
|
21
|
+
:I => [2.36,9.68,nil],
|
22
|
+
:L => [2.36,9.60,nil],
|
23
|
+
:V => [2.32,9.62,nil],
|
24
|
+
:P => [1.99,10.96,nil],
|
25
|
+
:A => [2.34,9.69,nil],
|
26
|
+
:G => [2.34,9.60,nil],
|
27
|
+
# These are the fringe cases... B and Z... Jerks, these are harder to calculate pIs
|
28
|
+
:B => [1.95,9.20,3.65],
|
29
|
+
:Z => [2.18,9.40,4.25],
|
30
|
+
:X => [2.20,9.40,nil],
|
31
|
+
:U => [1.96,10.28,5.20] # Unfortunately, I've only found the pKr for this... so I've used Cysteine's values.
|
32
32
|
}
|
33
33
|
PepCharges = Struct.new(:seq, :n_term, :c_term, :y_num, :c_num, :k_num, :h_num, :r_num, :d_num, :e_num, :u_num, :polar_num, :hydrophobic_num, :pi)
|
34
34
|
def identify_potential_charges(str)
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
35
|
+
string = str.upcase
|
36
|
+
first = string[0]; last = string[-1]
|
37
|
+
puts string if first.nil? or last.nil?
|
38
|
+
begin
|
39
|
+
out = PepCharges.new(string, ResidueTable[first.to_sym][0], ResidueTable[last.to_sym][1], 0, 0, 0 ,0 ,0 ,0, 0, 0, 0, 0, 0)
|
40
|
+
rescue NoMethodError
|
41
|
+
abort string
|
42
|
+
end
|
43
|
+
string.chars.each do |letter|
|
44
|
+
case letter
|
45
|
+
when "Y"
|
46
|
+
out.y_num += 1
|
47
|
+
when "C"
|
48
|
+
out.c_num += 1
|
49
|
+
when "K"
|
50
|
+
out.k_num += 1
|
51
|
+
when "H"
|
52
|
+
out.h_num += 1
|
53
|
+
when "R"
|
54
|
+
out.r_num += 1
|
55
|
+
when "D"
|
56
|
+
out.d_num += 1
|
57
|
+
when "E"
|
58
|
+
out.e_num += 1
|
59
|
+
when "U"
|
60
|
+
out.u_num += 1
|
61
|
+
when "S", "T", "N", "Q"
|
62
|
+
out.polar_num += 1
|
63
|
+
when "A", "V", "I", "L", "M", "F", "W", "G", "P"
|
64
|
+
out.hydrophobic_num += 1
|
65
|
+
end
|
66
|
+
end
|
67
|
+
out
|
68
68
|
end # Returns the PepCharges structure
|
69
69
|
|
70
70
|
def charge_at_pH(pep_charges, pH)
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
71
|
+
charge = 0
|
72
|
+
charge += -1/(1+10**(pep_charges.c_term-pH))
|
73
|
+
charge += -pep_charges.d_num/(1+10**(ResidueTable[:D][2]-pH))
|
74
|
+
charge += -pep_charges.e_num/(1+10**(ResidueTable[:E][2]-pH))
|
75
|
+
charge += -pep_charges.c_num/(1+10**(ResidueTable[:C][2]-pH))
|
76
|
+
charge += -pep_charges.y_num/(1+10**(ResidueTable[:Y][2]-pH))
|
77
|
+
charge += 1/(1+10**(pH - pep_charges.n_term))
|
78
|
+
charge += pep_charges.h_num/(1+10**(pH-ResidueTable[:H][2]))
|
79
|
+
charge += pep_charges.k_num/(1+10**(pH-ResidueTable[:K][2]))
|
80
|
+
charge += pep_charges.r_num/(1+10**(pH-ResidueTable[:R][2]))
|
81
|
+
charge
|
82
82
|
end
|
83
83
|
|
84
84
|
|
85
85
|
def calc_PI(pep_charges)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
86
|
+
pH = 8; pH_prev = 0.0; pH_next = 14.0
|
87
|
+
charge = charge_at_pH(pep_charges, pH)
|
88
|
+
while pH-pH_prev > Precision and pH_next-pH > Precision
|
89
|
+
if charge < 0.0
|
90
|
+
tmp = pH
|
91
|
+
pH = pH - ((pH-pH_prev)/2)
|
92
|
+
charge = charge_at_pH(pep_charges, pH)
|
93
|
+
pH_next = tmp
|
94
|
+
else
|
95
|
+
tmp = pH
|
96
|
+
pH = pH + ((pH_next - pH)/2)
|
97
|
+
charge = charge_at_pH(pep_charges, pH)
|
98
|
+
pH_prev = tmp
|
99
|
+
end
|
100
|
+
# puts "charge: #{charge.round(2)}\tpH: #{pH.round(2)}\tpH_next: #{pH_next.round(2)}\tpH_prev: #{pH_prev.round(2)}"
|
101
|
+
end
|
102
|
+
pH
|
103
103
|
end
|
104
|
-
|
105
|
-
=
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
=
|
113
|
-
=
|
114
|
-
|
115
|
-
|
116
|
-
|
104
|
+
def distribution_from_charge(charge, normalization=100)
|
105
|
+
threshold = normalization.to_f
|
106
|
+
f = charge.floor
|
107
|
+
c = charge.ceil
|
108
|
+
charge_ratio = charge - f
|
109
|
+
num = charge_ratio*normalization
|
110
|
+
denom = normalization
|
111
|
+
while num + denom > threshold
|
112
|
+
factor = threshold/(num+denom)
|
113
|
+
num = num * factor
|
114
|
+
denom = denom * factor
|
115
|
+
end
|
116
|
+
[["+#{f}" + ", " + "%5f" % num],["+#{c}" + ", " + "%5f" % denom]]
|
117
117
|
end
|
118
|
-
=end
|
119
|
-
#out_pi = pepcharges.map {|a| calc_PI(a)}
|
120
118
|
|
121
|
-
|
122
|
-
#
|
119
|
+
|
120
|
+
#pepcharges =[]
|
121
|
+
if $0 == __FILE__
|
122
|
+
VERBOSE = false
|
123
|
+
def putsv(object)
|
124
|
+
puts object if VERBOSE
|
125
|
+
end
|
126
|
+
def out(line, object)
|
127
|
+
line + ":\t" + object.to_s
|
128
|
+
end
|
129
|
+
require 'optparse'
|
130
|
+
|
131
|
+
options = {pi: true, distribution: false, ph: 7.0}
|
132
|
+
parser = OptionParser.new do |opts|
|
133
|
+
opts.banner = "Takes strings and outputs the PI, or charge distribution"
|
134
|
+
|
135
|
+
opts.on('-h','--help', "Displays this help message") do |h|
|
136
|
+
puts opts
|
137
|
+
exit
|
138
|
+
end
|
139
|
+
opts.on('-v','--verbose') {|v| VERBOSE = v}
|
140
|
+
opts.on("--[no]-pi", "Turns on (default) or off the pI output") do |p|
|
141
|
+
options[:pi] = p
|
142
|
+
end
|
143
|
+
opts.on("-d", "--distribution", "Output a string representation of the charge state distribution array") do |d|
|
144
|
+
options[:distribution] = true
|
145
|
+
options[:pi] = false
|
146
|
+
end
|
147
|
+
opts.on('--pH N', Float, "Takes a float value representing a pH at which to make the distribution. DEFAULT: 7.0") do |ph|
|
148
|
+
options[:ph] = ph
|
149
|
+
end
|
150
|
+
opts.on('-f', "--file FILENAME", String, "Takes an input file for parsing") do |f|
|
151
|
+
options[:in_file] = f
|
152
|
+
end
|
153
|
+
end
|
154
|
+
parser.parse!
|
155
|
+
|
156
|
+
# RUN
|
157
|
+
pi = []
|
158
|
+
lines = []
|
159
|
+
if options[:in_file]
|
160
|
+
file_lines = File.readlines(options[:in_file]).map(&:chomp)
|
161
|
+
lines = file_lines.map {|line| line[/^([A-Z]+).*/] }.compact
|
162
|
+
outfile = File.join(File.dirname(options[:in_file]), 'pi_output_file.txt')
|
163
|
+
outputter = File.open(outfile,'w')
|
164
|
+
else
|
165
|
+
lines = ARGV
|
166
|
+
outputter = STDOUT
|
167
|
+
end
|
168
|
+
if options[:pi]
|
169
|
+
lines.each {|line| outputter.puts out(line, calc_PI(identify_potential_charges(line)) ) }
|
170
|
+
elsif options[:distribution]
|
171
|
+
lines.each do |line|
|
172
|
+
charge = charge_at_pH(identify_potential_charges(line), options[:ph])
|
173
|
+
charge_dist = distribution_from_charge(charge)
|
174
|
+
outputter.puts out(line + " @ pH #{options[:ph]}", charge_dist.join("; "))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
if outfile
|
178
|
+
outputter.close
|
179
|
+
puts "OUTPUT in #{outfile}"
|
180
|
+
end
|
181
|
+
end
|